允许未经确认的用户访问某些需要身份验证的页面
Allow unconfirmed users to access certain pages which require authentication
我使用 Rails 堆栈
- 设计
- 典狱长
- 可确认
现在我有一个与电子邮件确认和向未经验证的用户提供访问权限相关的特定要求。假设有 3 类页面:
case 1
- 不需要身份验证。
case 2
- 需要身份验证,还需要确认用户。
case 3
- 需要身份验证(正确的用户名和密码组合)但无需确认用户即可访问它们。
通过设计和确认,实施 case 1
和 case 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
它工作得非常好,尤其是在您确定针对某种资源的授权的其他情况下。
我使用 Rails 堆栈
- 设计
- 典狱长
- 可确认
现在我有一个与电子邮件确认和向未经验证的用户提供访问权限相关的特定要求。假设有 3 类页面:
case 1
- 不需要身份验证。case 2
- 需要身份验证,还需要确认用户。case 3
- 需要身份验证(正确的用户名和密码组合)但无需确认用户即可访问它们。
通过设计和确认,实施 case 1
和 case 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
它工作得非常好,尤其是在您确定针对某种资源的授权的其他情况下。