【问题标题】:Devise+CanCan AccessDenied redirect differs between dev and test environmentsDevise+CanCan AccessDenied 重定向在开发环境和测试环境之间有所不同
【发布时间】:2011-08-11 21:52:34
【问题描述】:

我有一个带有 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

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

【问题讨论】:

  • 您是否仔细检查了是否调用了rescue_from CanCan::AccessDenied 块?
  • 这基本上就是重点 - 它没有在测试环境中被调用。为了验证这一点,我在rescue_from块中添加了一个日志语句(在重定向之前),它在运行我的集成测试时没有出现在测试日志中,但它确实出现在了开发日志中。

标签: ruby-on-rails devise integration-testing cancan


【解决方案1】:

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

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

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

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

如果您发布您的设计配置/代码,我们或许可以帮助您进一步调试。

编辑/TLDR:

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

【讨论】:

  • 请解释更多 - 根据文档 (github.com/plataformatec/devise) 没有任何设计配置可放入 ApplicationController。在我的最后一段中,我提到在测试中用户按预期登录 - 我有几个不同的测试断言来验证这一点。
  • 添加了简洁的 TLDR。重定向到登录是 sign_in() 不起作用的吸烟枪。
  • 您基本上是正确的 - 我在问题的底部添加了更多细节。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-05
相关资源
最近更新 更多