Devise + CanCan AccessDenied重定向在开发人员和测试环境之间有所不同 [英] Devise+CanCan AccessDenied redirect differs between dev and test environments

查看:382
本文介绍了Devise + CanCan AccessDenied重定向在开发人员和测试环境之间有所不同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Rails 3.1(RC5)应用程序与Devise和CanCan。两者都配置良好,按预期工作,除了当我运行集成测试以确保AccessDenied根据需要重定向时,重定向到Devise的登录而不是应用程序根目录。我可以在我的测试中验证用户是否仍然登录,仍然可以访问应用程序的相应部分。



重定向在此短控制器中定义,其他受限制的控制器继承(而不是直接继承ApplicationController)。

  class AuthorizedController< ApplicationController 
before_filter:authenticate_user!

rescue_from CanCan :: AccessDenied do | exception |
redirect_to root_url,:alert => exception.message
end
end

受限制的控制器如下所示: / p>

  class Admin :: UsersController< AuthorizedController 
load_and_authorize_resource
def index
@users = User.all.order('name')
end
...
end
我正在使用默认(ActionDispatch :: IntegrationTest)集成测试;



<我唯一的额外的测试宝石是水豚,机械师和Faker(没有RSpec,黄瓜等)。



我的测试看起来像:

  def test_user_permissions 
sign_in users(:user)
get admin_users_path
assert_response:redirect
assert_redirected_to root_url
end

测试失败:

 预期响应将重定向到< http://www.example.com/>但是重定向到< http://www.example.com/users/sign_in> 

当我通过在我的开发环境中作为受限制的用户登录进行测试时,我被重定向到 /',但在集成测试中使用相同类型的用户失败。



在集成测试中,用户实际上并没有注销,尽管重定向使它看起来像这样发生。当我将测试更改为不测试重定向目标并继续尝试其他URL时,用户仍然会登录,测试通过。



附录和解决方案:



我原来没有包含持有关键线索的sign_in方法。这里是:

  module ActionController 
class IntegrationTest
include Capybara :: DSL
def sign_in(user,password ='Passw0rd')
sign_out
访问root_path
fill_in'Email',:with => user.email
fill_in'Password',:with =>密码
click_button'登录'
signed_in?用户
end
...
end
end

我在 sign_in中混合了Capybara访问方法(访问 click_button 等) 和vanilla集成测试访问方法( get 等)在测试中。当我使用Webrat(在Capybara之前),这个混合按照我的预期工作,但显然Capybara的会话状态是单独处理的,所以通过Capybara方法的访问被认证,但是通过香草集成测试方法进行访问不是。

解决方案

您没有在ApplicationController中发布您的设计配置,但它看起来像是在CanCan授权检查之前加载的身份/登录检查(这是有道理的)。



看起来你的测试登录设置不正常,因为'/ users / sign_in'是devise的默认重定向不是一个有效的用户会话。



由于设计身份检查失败,所以不会打到CanCan授权检查。如果没有用户,为什么要问用户可以做什么?



before_filters将从基础ApplicationController首先按照它们被定义的顺序从链上执行,所以子类过滤器在基类过滤器之后。这就是为什么我认为你的基础应用程序控制器中有Devise配置,导致这不能打CanCan。



如果你发布你的Devise配置/代码,我们可能能够帮助您进一步调试。



编辑/ TLDR:



您正在看到重定向到登录,因为Devise doesn不要认为有效的用户会话存在。您的测试sign_in()帮助器不能按照您的想法运行。这就是为什么这可以通过手动登录在开发模式下进行实时用户会话。


I have a Rails 3.1 (RC5) app with Devise and CanCan. Both are configured well and working as expected except that when I run integration tests to ensure that AccessDenied is being redirected as desired, the redirect goes to Devise's sign in instead of the application root. I can verify in my test that the user is still logged in and can still access applicable parts of the app.

The redirect is defined in this short controller, which the other restricted controllers inherit (instead of directly inheriting ApplicationController).

class AuthorizedController < ApplicationController
  before_filter :authenticate_user!

  rescue_from CanCan::AccessDenied do |exception|
    redirect_to root_url, :alert => exception.message
  end
end

The restricted controllers look like this:

class Admin::UsersController < AuthorizedController
  load_and_authorize_resource
  def index
    @users = User.all.order('name')
  end
  ...
end

I am using the default (ActionDispatch::IntegrationTest) integration test; the only additional testing gems I have are Capybara, Machinist, and Faker (no RSpec, Cucumber, etc.).

My test looks like:

def test_user_permissions
  sign_in users(:user)
  get admin_users_path
  assert_response :redirect
  assert_redirected_to root_url
end

The test fails with:

Expected response to be a redirect to <http://www.example.com/> but was a redirect to <http://www.example.com/users/sign_in>

When I test this by logging in as a restricted user in my dev environment, I am redirected to '/' as expected, but using the same type of user in the integration tests fails.

In the integration tests, the user is not actually being logged out, although the redirect makes it look like that is happening. When I change the test to not test the redirection target and continue trying other URLs, the user is still logged in and the test passes.

Addendum & Solution:

I originally did not include the sign_in method that held the key clue. Here it is:

module ActionController
  class IntegrationTest
    include Capybara::DSL
    def sign_in (user, password = 'Passw0rd')
      sign_out
      visit root_path
      fill_in 'Email',    :with => user.email
      fill_in 'Password', :with => password
      click_button 'Sign in'
      signed_in? user
    end
    ...
  end
end

I was mixing Capybara access methods (visit, click_button, etc.) in sign_in and vanilla integration test access methods (get, etc.) in the test. When I used Webrat (before Capybara) this mixing worked as I expected, but evidently Capybara's session state is handled separately, so access via the Capybara methods was authenticated, but access via the vanilla integration test methods was not.

解决方案

You didn't post your devise config in ApplicationController, but it looks like the devise Identity/Sign-in checks are loading up before the CanCan Authorization checks (which makes sense).

It looks like your test sign in setup isn't working correctly, because '/users/sign_in' is the default redirect for devise when there isn't a valid user session.

Because the devise identity check is failing, it's never hitting your CanCan Authorization check. Why ask what the user can do if there isn't a user yet.

The before_filters will execute from the base ApplicationController first on up the chain in the order they are defined, so subclass filters after base class filters. This is why I think you've got Devise config in your base ApplicationController causing this not to hit CanCan.

If you post your Devise config/code we may be able to help you debug it further.

EDIT / TLDR:

You are seeing a redirect to login because Devise doesn't think a valid user session exists. Your test "sign_in()" helper isn't working the way you think it is. That's why this works in dev mode with a live user session via manual login.

这篇关于Devise + CanCan AccessDenied重定向在开发人员和测试环境之间有所不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆