Devise+CanCan AccessDenied 重定向在开发环境和测试环境之间有所不同

发布于 2024-11-29 10:28:36 字数 1961 浏览 0 评论 0原文

我有一个带有 Devise 和 CanCan 的 Rails 3.1 (RC5) 应用程序。两者都配置良好并且按预期工作,只是当我运行集成测试以确保 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

受限控制器如下所示:

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

我正在使用默认的 (ActionDispatch::IntegrationTest) 集成测试;我唯一拥有的额外测试宝石是 Capybara、Machinist 和 Faker(没有 RSpec、Cucumber 等)。

我的测试如下所示:

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

测试失败并显示:

Expected response to be a redirect to <http://www.example.com/> but was a redirect to <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
      visit root_path
      fill_in 'Email',    :with => user.email
      fill_in 'Password', :with => password
      click_button 'Sign in'
      signed_in? user
    end
    ...
  end
end

我在 sign_in 中混合了 Capybara 访问方法(visitclick_button 等)和普通集成测试访问方法(>get 等)在测试中。当我使用 Webrat(在 Capybara 之前)时,这种混合按我的预期工作,但显然 Capybara 的会话状态是单独处理的,因此通过 Capybara 方法的访问经过身份验证,但通过普通集成测试方法的访问则不然。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

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

您的测试登录设置似乎无法正常工作,因为当没有有效的用户会话时,“/users/sign_in”是 devise 的默认重定向。

由于设备身份检查失败,因此它永远不会达到您的 CanCan 授权检查的要求。如果还没有用户,为什么要问用户可以做什么。

before_filters 将按照定义的顺序首先从基础 ApplicationController 执行,因此子类过滤器在基类过滤器之后执行。这就是为什么我认为你在基础 ApplicationController 中进行了 Devise 配置,导致它不会命中 CanCan。

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

编辑/TLDR:

您看到登录重定向,因为 Devise 认为不存在有效的用户会话。您的测试“sign_in()”助手未按您想象的方式工作。这就是为什么它可以在开发模式下通过手动登录进行实时用户会话。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文