【问题标题】:Rails 4 - Devise, guest users causes filter chain haltedRails 4 - 设计,来宾用户导致过滤器链停止
【发布时间】:2016-02-18 02:38:22
【问题描述】:

我刚刚开始开发 Rails 4 (4.2.3) 应用程序,我使用 Devise 进行用户身份验证。我希望用户能够在注册 upp 之前通过创建一个测试项目并以访客用户身份登录来使用该应用程序。当用户注册(或注册)时,我想将测试项目分配给新的当前用户。

我一直在关注 Platformatec 的指南:https://github.com/plataformatec/devise/wiki/How-To:-Create-a-guest-user

创建来宾用户有效,但在注册或使用活动的来宾用户会话时,我收到以下错误:

Filter chain halted as :require_no_authentication rendered or redirected

如果我清除我的会话,它会起作用。管理我的访客用户的方法如下所示:

def current_or_guest_user
  if current_user
    if session[:guest_user_id] && session[:guest_user_id] != current_user.id
      logging_in
      guest_user(with_retry = false).try(:destroy)
      session[:guest_user_id] = nil
    end
    current_user
  else
    guest_user
  end
end

如前所述,创建来宾用户似乎工作得很好。但这种逻辑永远不会发生:

# should delete the guest user and clear the session. 
if current_user
  if session[:guest_user_id] && session[:guest_user_id] != current_user.id
    logging_in
    guest_user(with_retry = false).try(:destroy)
    session[:guest_user_id] = nil
  end
  current_user

我很确定我的来宾用户会话与我的新用户冲突并导致此设计错误(因为来宾用户在注册时永远不会被删除):

Filter chain halted as :require_no_authentication rendered or redirected

我的访客用户逻辑的其余部分看起来或多或少与此链接指南完全相同:https://github.com/plataformatec/devise/wiki/How-To:-Create-a-guest-user。我还添加了身份验证段落/示例中的代码:https://github.com/plataformatec/devise/wiki/How-To:-Create-a-guest-user#authentication-this-may-interfere-with-the-current_user-helper

关于我缺少什么的任何想法,以及如何让我的current_or_guest_user 在使用 Devise 时删除注册和签名的来宾用户?

更新

这是我的路线目前的样子:

devise_for :users, controllers: { sessions: "users/sessions", registrations:  "users/registrations" }

root :to => 'public#index'

resources :apps

get 'users/show', to: "users#show"
get 'users', to: "users#index"

post 'guests/receive_guest', to: "guests#receive_guest"

更新 2

该指南有以下声明:

当(如果)用户注册或登录时,我们会删除访客用户 并清除会话变量。

它并没有解释如何以及在哪里做。我猜我必须再次致电current_or_guest_user。但我不确定在哪里,因为我对 Devise 不太熟悉。

更新 3

为了更清楚一点。这是我想要实现的步骤。

  1. 用户创建一个测试项目。
  2. 创建测试项目后,会创建来宾用户和会话。一旦会话结束或#3,访客用户应该被删除。
  3. 如果来宾用户注册,他/她应该登录并且测试项目应该分配给新的真实用户。
  4. 应该删除来宾用户。

【问题讨论】:

  • 你能发布你的routes.rb文件吗?
  • @huzefabiyawarwala 我已经做到了。
  • 我已经尝试了与您尝试在我的机器上实现的相同的方法,并且效果很好,因此除了设计之外,您编写的附加代码中可能缺少某些内容。如果可能,请删除上面的代码并发布您当前拥有的确切控制器。那会更容易调试。
  • 你能更新你的guest_user(with_retry = false).try(:destroy) 行来喜欢那个guest_user(with_retry = false).reload.try(:destroy)
  • @KhAmmad 我可以。然而,问题是这个 if 语句 session[:guest_user_id] && session[:guest_user_id] != current_user.id 目前永远不会成为真的。我猜我必须再次致电current_or_guest_user,但我不确定何时何地。

标签: ruby-on-rails ruby ruby-on-rails-4 authentication devise


【解决方案1】:

上面的答案缺乏解释,loggin_in 方法没有被调用,因为你没有定义你的回调

在您的 ApplicationController 中,您需要像这样定义然后设置回调:

define_callbacks :logging_in_user
set_callback :logging_in_user, :before, :transfer_guest_user_actions_to_current_user

def transfer_guest_user_actions_to_current_user
  # todo
end

您是否尝试过使用devise-guests gem?它实现了开箱即用的这个功能,而不是从头开始......

检查这个正在实现访客登录的example 控制器。希望对您有所帮助。

【讨论】:

  • 谢谢。将调查您的解决方案。似乎是一种干净的方法。我在下面创建了一个答案,说明我现在是如何做到的,至少让它工作。随时提出改进建议。
【解决方案2】:

我认为该问题是由指南中引用的 guest_user 守望者策略引起的。 由于 Devise 在登录前会检查有效的warden 会话,因此会导致重定向并显示一条闪现消息:

if authenticated && resource = warden.user(resource_name)
  flash[:alert] = I18n.t("devise.failure.already_authenticated")
  redirect_to after_sign_in_path_for(resource)
end

因此,如果您不严格需要该身份验证!方法来处理来宾用户,您可以简单地停用该策略,它应该可以工作。

【讨论】:

  • 谢谢。那确实有帮助。我已经为我在下面所做的一切创建了一个完整的答案。如果您知道更好的方法,请随时对其进行改进。谢谢!
【解决方案3】:

感谢您的回答 skahlert 和 SsouLlesS。跳过守望者策略确实有帮助,定义回调似乎是一种干净的方法。除此之外,我还有一些其他问题。

一个是我的自定义设计控制器从未被调用。为此创建了另一个问题:Rails 4 - devise_for not using custom controllers。解决方案是我在模态注册表单中使用了错误的 url。我的表单现在看起来像这样:

= form_for(resource, as: resource_name, url: user_registration_path do |f|

然后我按照 skahlert 的建议做了,并从我的应用程序中删除了 warden strategy

一旦我的自定义设计Users::RegistrationsController < Devise::RegistrationsController 控制器被调用,我决定重写创建操作。它没有完全测试,但看起来像这样:

# POST /resource
def create
  # Delete guest user and reset session. 
  new_user_from_guest = guest_user
  guest_user(with_retry = false).try(:destroy)
  session[:guest_user_id] = nil

  build_resource(sign_up_params)

  resource.save
  yield resource if block_given?
  if resource.persisted?
    if resource.active_for_authentication?
      set_flash_message :notice, :signed_up if is_flashing_format?
      sign_up(resource_name, resource)

      # Assign the guest users app to the new current user.
      new_user_from_guest.apps.each do |app|
        app.user_id = current_user.id
        app.save!
      end
      respond_with resource, location: after_sign_up_path_for(resource)
    else
      set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_flashing_format?
      expire_data_after_sign_in!
      respond_with resource, location:  after_inactive_sign_up_path_for(resource)
    end
  else
    # Reset test user if signup fails, I have not tested this part yet. 
    guest_user
    guest_user.apps << new_user_from_guest.apps
    guest_user.save!

    clean_up_passwords resource
    set_minimum_password_length
    respond_with resource
  end
end

现在似乎一切正常。可以进行一些重构,并可能尝试 SsouLlesS 在他的回答中建议的回调方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-03-19
    • 2019-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多