当用户(没有登录)遵循我在电子邮件中发送给他们的确认链接时,用户确认是如何工作的:
更新:好的,考虑一下,用户确认只是为了测试电子邮件地址的存在,而与安全性无关。说到这里,我仍然想知道如何改变表单的重定向方向,以这个问题为例。
他们沿着确认路径->重定向在表单->中签名,他们在正确的->中签名,他们必须再次遵循链接,->,他们到达确认动作->,他们被确认了
这有点笨拙。我宁愿这样做:
他们沿着确认路径->重定向在表单->中签名,他们正确地在->中签名,他们到达确认动作->,他们被确认了
我想消除第二次遵循链接的需要,但我不知道如何继续这样做。这是我的sign_in表格:
<%= form_for(:session, url: sessions_path) do |f| %>
<%= f.label 'Email address' %><br>
<%= f.text_field :email, class: 'form-control', placeholder: 'Enter email' %><br>
<%= f.label 'Password' %><br>
<%= f.password_field :password, class: 'form-control', placeholder: 'Enter password' %><br>
<%= f.submit 'Sign In', class: 'btn btn-default' %>
<% end %>它将其参数传递给我的sessions#create操作:
def create
user = User.find_by(email: params[:session][:email].downcase )
if user && user.authenticate(params[:session][:password])
sign_in(user)
redirect_to user_path(current_user)
else
flash.now[:error] = 'Wrong email or password!'
render 'new'
end
end现在我相信关键就在行动的第5行:
redirect_to user_path(current_user)这需要改变。我相信我能在这里搞到一些东西,但我想知道你将如何处理这个问题。
发布于 2014-04-30 00:36:51
说到这里,我仍然想知道如何改变表单的重定向方向,以这个问题为例。
我可以给你一个想法和最普遍的做法,大家都遵循。
如果用户未登录并重定向到该部分,则只需保存请求的路径即可。设计创业板也使用同样的策略,如果你使用的话,你可以利用它的优势。
我是在描述一般的解决办法。要保存和获取存储位置,需要在application控制器中使用两种方法
store_location:用于存储位置,所以我们将在登录后重定向它。
def store_location(location)
if location
uri = URI.parse(location)
session["return_path"] = [uri.path.sub(/\A\/+/, '/'), uri.query].compact.join('?')
end
endstored_location:用于检索保存的位置(尝试定位)。同时删除会话路径(我将在最后部分对其进行解释)。
def stored_location
location = session["return_path"]
session.delete("return_path")
location
end你必须在你的confirmation控制器中做这样的事情
before_action: authenticated!
def authenticated!
unless signed_in?
store_location_for(request.original_url)
redirect_to sign_in_path
end
end您只需自定义session#create控制器,这样的东西会工作。
redirect_to stored_location || user_path(current_user)现在,考虑一下你的女儿
session.delete("return_path"). 我希望这能说明清楚。
PS:上面的代码是抽象的,如果您有基于角色的应用程序,您必须对位置进行不同的范围调整,我还没有解释这件事,因为它远远超出了这个主题。如果你想学得更多,你可以读 gem specs
发布于 2014-04-25 16:45:50
根据我们的意见,我首先创建一个确认模型。
rails g model Confirmation key:string user_id:integer可以使用回调生成随机散列:
require 'securerandom'
...
before_validation :generate_random_key
belongs_to :user
validates_uniqueness_of :user_id
...
private
def generate_random_key
self.key = SecureRandom.hex(32)
end然后,用于创建新注册的控制器为新用户向该模型添加一条记录。此外,User模型有一个has_one :confirmation关系是合适的。(Rails has_one实际上意味着0或1。)
接下来,使用确认控制器将用户的状态设置为“确认”。类似于:
rails g controller confirmation new然后我会编辑config/routes.rb以使用单一的CRUD资源路径,因为只有
resource :confirmation, only: :new这样,您的电子邮件中的路径应该如下所示:
.../confirmation?key=<long hex string>控制员:
class ConfirmationController < ApplicationController
def new
key = params[:key]
user = key && User.joins(:confirmation).where(key: key)
if user
user.confirmation.destroy # Kill the confirmation. It's not needed any more.
user.confirmed = true # Mark the user confirmed
user.save! # Update her record.
flash[:alert] = 'Your registration has been confirmed. Log in for full service!'
else
flash[:error] = 'Your confirmation link is broken or expired. Log in to request a new one.'
end
redirect_to controller: :sessions, :action: :new
end
end会话控制器应该重定向到一个“无服务”登陆页面,该页面在未经确认的用户登录时显示。只有一件事会有一个链接,要求一个新的确认电子邮件。对于确认的用户登录,它将重定向到完整的服务登陆页面。
在创建新的确认记录之前,删除用户存在的任何旧确认记录。如果需要,可以使用后台作业过期未使用的作业。
发布于 2014-05-02 22:18:33
我更喜欢将重定向URL作为参数传递给Paritosh解决方案的变体,而不是将其存储在会话中。它更容易受到XSS攻击(因此您在重定向时需要小心验证),但如果用户在登录前打开多个选项卡到站点上的不同页面,则不会中断。这是我最讨厌的事。)
基本思想是,当重定向到表单中的符号时,身份验证检查总是在目标路径上传递:
# Variation on Paritosh's solution
before_action: authenticated!
def authenticated!
unless signed_in?
uri = URI.parse(request.original_url)
redirect_to sign_in_path(redirect_path: [uri.path.sub(/\A\/+/, '/'), uri.query].compact.join('?'))
end
end然后,您的表单中的签名将该路径与用户名和密码一起传递出去。
<%= form_for(:session, url: sessions_path) do |f| %>
<%= hidden_field_tag(:redirect_path, params[:redirect_path]) if params[:redirect_path] %>
<%= f.label 'Email address' %><br>
<%= f.text_field :email, class: 'form-control', placeholder: 'Enter email' %><br>
<%= f.label 'Password' %><br>
<%= f.password_field :password, class: 'form-control', placeholder: 'Enter password' %><br>
<%= f.submit 'Sign In', class: 'btn btn-default' %>
<% end %>然后会话控制器重定向到该路径(如果有效的话)
def create
user = User.find_by(email: params[:session][:email].downcase )
if user && user.authenticate(params[:session][:password])
sign_in(user)
redirect_path redirect_path || user_path(current_user)
else
flash.now[:error] = 'Wrong email or password!'
render 'new'
end
end
private
def redirect_path
params[:redirect_path] if params[:redirect_path] && params[:redirect_path] =~ /\A\/[^\/]/
end如果您使用子域作为服务中的登录,则可以传递完整的URL,而不仅仅是路径。在这种情况下,您需要验证URL中的主机名是否是您拥有的主机名。
https://stackoverflow.com/questions/23283711
复制相似问题