Con*_*lon 5 ruby-on-rails devise devise-confirmable
我让用户最初登录时没有确认他们的电子邮件地址 - 但是在7天之后,如果他们还没有确认 - 我阻止访问,直到他们确认他们的地址.
(注意 - 这可以通过设置config.allow_unconfirmed_access_for = 7.daysDevise初始化程序来实现)
如果他们达到'宽限'限制(例如他们没有确认并且7天通过)那么我想:
做#2我需要访问用户才能获得电子邮件地址.
设计显然"知道"用户是谁 - 这就是它知道他们已经通过确认到期的方式.
如果用户刚刚尝试登录,那么我可以通过查看参数来获得此信息.但是,如果用户已经在他们的会话中有一个实时登录令牌,那么当他们通过神奇的一周 - 他们将突然开始被设计拒绝.在这种情况下如何访问用户?
#based on
#https://github.com/plataformatec/devise/wiki/How-To:-Redirect-to-a-specific-page-when-the-user-can-not-be-authenticated
#https://stackoverflow.com/questions/9223555/devise-with-confirmable-redirect-user-to-a-custom-page-when-users-tries-to-sig
class CustomFailure < Devise::FailureApp
def redirect_url
if warden_message == :unconfirmed
user = User.find_by_email(params.dig(:user,:email))
user&.send_confirmation_instructions
if user.nil?
#if the user had a valid login session when they passed the grace period, they will end up here
!! how do I get the user in this scenario !!
end
confirmation_required_info_path(params: {found: !user.nil?})
elsif warden_message == :invalid
new_user_session_path(user:{email: params.dig(:user,:email)})
else
super
end
end
# You need to override respond to eliminate recall
def respond
if http_auth?
http_auth
else
redirect
end
end
end
Run Code Online (Sandbox Code Playgroud)
这实现了目标#1,但是如果失败是新注册的结果,它只实现目标#2
是否有直接的方式来访问用户有一个实时会话,但已经过了有效期?
(current_user不可用,env ['warden'].user is nil)
谢谢
Rails 5.0.6设计4.2
编辑:更新以澄清我需要帮助的示例场景:
第0天:用户使用电子邮件/密码注册.我告诉他们没有确认他们的电子邮件.他们有7天的宽限期来确认他们的电子邮件.
第2天:他们退出了
第7天(早上):他们再次登录
第7天(当天晚些时候):他们采取了一些行动.他们的登录令牌仍然有效 - 设计识别它,找到他们的用户记录并检查他们是否已确认他们的电子邮件地址.他们没有 - 所以设计拒绝授权行动,给出错误:未经证实
在这种情况下 - 他们来到失败应用程序.我会将它们重定向到一个页面,上面写着"你已经过了7天的宽限期,你真的需要立即确认你的电子邮件地址".
在失败应用程序中,我想知道他们的电子邮件地址是什么,以便我可以自动重新发送确认电子邮件.我怎么得到这个?
注意 - 在这种情况下,设计已拒绝授权.current_user是零.然而,Devise清楚地"知道"用户是谁 - 因为它能够在数据库中查找他们的记录,并检查他们是否已经过了未经证实的电子邮件地址的宽限期.我如何获得相同的"知识"
小智 3
我认为有更好的方法可以实现相同的结果而无需创建Devise::FailureApp:
这可以通过覆盖模块confirmed?中存在的 Devise 资源扩展中的方法来实现。Confirmable
一个简单的例子是:
delayed_confirmation_expiry_date到模型的表中。该字段将用于存储用户首次注册到您的应用程序时的到期日期时间。您必须SessionsController#create为此重写该方法,以便它可以调用#delay_confirmation!您的资源上的方法。
User等效项:# Will update the field you have added with the new temporary expiration access datetime
def delay_confirmation!(expiry_datetime=7.days.from_now)
self.delayed_confirmation_expiry_date = expiry_datetime
self.save
end
# Override that will make sure that, once the user is confirmed, the delayed confirmation information is cleared
def confirm(args={})
clear_delay_confirmation!
super
end
# Self-explanatory
def clear_delay_confirmation!
self.delayed_confirmation_expiry_date = nil
self.save
end
# Used on your controllers to show messages to the user warning him about the presence of the confirmation delay
def confirmation_is_delayed?
self.confirmed? && !self.confirmed_at.present?
end
# Overrides the default implementation to allow temporary access for users who haven't confirmed their accounts within the time limit
def confirmed?
if !self.confirmation_is_delayed?
super
else
self.delayed_confirmation_expiry_date >= DateTime.now.in_time_zone
end
end
Run Code Online (Sandbox Code Playgroud)