允许未经确认的用户访问某些需要身份验证的页面

Allow unconfirmed users to access certain pages which require authentication

我使用 Rails 堆栈

现在我有一个与电子邮件确认和向未经验证的用户提供访问权限相关的特定要求。假设有 3 类页面:

  1. case 1 - 不需要身份验证。
  2. case 2 - 需要身份验证,还需要确认用户。
  3. case 3 - 需要身份验证(正确的用户名和密码组合)但无需确认用户即可访问它们。

通过设计和确认,实施 case 1case 2 是一件轻而易举的事。一旦用户login/signup,我重定向到"confirm your email page"。

我的问题是 case 3。假设用户执行他的 login/signup。他尚未确认他的电子邮件地址,但应该被允许访问某些 case 3 路线。当他访问 case 3 路线时,我预计:

具有可确认性的设计要么允许确认用户访问所有页面,要么 none。它不允许访问某些经过身份验证但未经确认的页面。

我尝试通过实现此逻辑来覆盖设计 confirmed?

class ApplicationController < ActionController::Base
   before_filter :verify_user
   def verify_user
       $flag = true if CERTAIN_ROUTES.include?(action_class)
   end
end

class User < ActiveRecord::Base
   def confirmed?
      $flag || !!confirmed_at
   end
end

这几乎不能用于登录,但不能用于注册。此外,这是实现它的极其糟糕的方法。我应该如何处理这个问题?其他功能正常。

您可以直接覆盖 confirmation_required? 模型方法而不是覆盖 confirmed? (docs):

# user.rb
class User < ActiveRecord::Base
  protected

  def confirmation_required?
    false
  end
end

之后您可以自己处理确认逻辑,方法是在控制器需要确认时在 before_action 中重定向所有未确认的用户,或者您可以将其拉入您的授权逻辑(例如与专家)。

class ApplicationController < ActionController::Base
   def needs_confirmation
     redirect_to root_path unless current_user.confirmed?
   end
end

class SomeController < ApplicationController
  before_action :needs_confirmation
end

你应该看看 gem 'pundit' - 它与 devise 配合得很好。

https://github.com/varvet/pundit

无需编写控制器 before_actions 等,您编写的策略将涵盖您的每个授权要求,然后在您的控制器中使用这些策略。

例如,在控制器中:

class ExampleController < ApplicationController
    before_action { authorize :example }

    def case_one
       # action
    end

    def case_two
       # action
    end

    def case_three
       # action
    end
end

那么您的保单将保留在 app/policies/example_policy.rb

class ExamplePolicy < ApplicationPolicy
  attr_reader :user

  def initialize(user, _)
    @user = user
  end

  def case_one?
    true
  end

  def case_two?
    user.present? && user.confirmed_at.present?
  end

  def case_three?
    user.present?
  end
end

它工作得非常好,尤其是在您确定针对某种资源的授权的其他情况下。