[英]Devise Forgot Password for logged in user
我想知道是否有一種方法可以在不強制我的用戶注銷的情況下調用“忘記密碼”程序
我遇到的情況是:
由於 devise 需要密碼才能更改這些字段,因此用戶無法修改它們
我曾考慮過不強制設置密碼,但這對安全性沒有意義,所以我只是將字段顯示為文本並通知用戶按照“忘記密碼”程序來設置密碼和然后他們可以更改字段
那么問題是我不能簡單地從用戶個人資料鏈接到這個,因為 devise 會告訴用戶他們不能在已經登錄的情況下這樣做。
那么有沒有一種方法可以覆蓋忘記密碼或 /users/password/edit 方法,以便登錄用戶也可以執行此操作?
您無法重置密碼的原因是設備嘗試使用當前會話對用戶進行身份驗證,並且當成功時,您將自動重定向到它應該去的任何路徑。 您需要的是覆蓋密碼控制器的編輯和更新操作,使其跳過此步驟。
這是代碼。 在您的密碼控制器中添加以下代碼(您可以請設計為您生成控制器,或者您可以創建以下控制器)。 更新覆蓋是必要的,否則登錄用戶將在重置密碼后自動注銷。 (或者,如果你希望它像你那樣可以擺脫#update覆蓋)
class PasswordsController < Devise::PasswordsController
# here we need to skip the automatic authentication based on current session for the following two actions
# edit: shows the reset password form. need to skip, otherwise it will go directly to root
# update: updates the password, need to skip otherwise it won't even reset if already logged in
skip_before_filter :require_no_authentication, :only => [:edit, :update]
# we need to override the update, too.
# After a password is reset, all outstanding sessions are gone.
# When already logged in, sign_in is a no op, so the session will expire, too.
# The solution is to logout and then re-login which will make the session right.
def update
super
if resource.errors.empty?
sign_out(resource_name)
sign_in(resource_name, resource)
end
end
end
路線如下
# config/routes.rb
devise_for :users, :controllers => {:passwords => 'passwords'}
您可以使用@user.send_reset_password_instructions
生成密碼重置令牌並發送電子郵件。 如果您只是直接調用郵件程序,則不會生成密碼重置令牌來驗證重置。
我在這里完整的解決方案,因為我還了解到用戶在點擊電子郵件中的鏈接后必須注銷,就是添加一些額外的UserController操作來實際編輯密碼並保存密碼。 這不是一個理想的解決方案,冷卻可能以更好的方式完成,但它對我有用。
用戶控制器; 添加了重置方法
before_filter :authenticate_user!, :except => [:do_reset_password, :reset_password_edit]
def reset_password
id = params[:id]
if id.nil?
id = current_user.id
end
if (!user_signed_in? || current_user.id.to_s != id.to_s)
flash[:alert] = "You don't have that right."
redirect_to '/home'
return
end
@user = User.find(id)
@user.send_reset_password_instructions
respond_to do |format|
format.html { redirect_to '/users/edit', notice: 'You will receive an email with instructions about how to reset your password in a few minutes.' }
end
end
def do_reset_password
id = params[:id]
if id.nil? && !current_user.nil?
id = current_user.id
end
if id.nil?
@user = User.where(:reset_password_token => params[:user][:reset_password_token]).first
else
@user = User.find(id)
end
if @user.nil? || @user.reset_password_token.to_s != params[:user][:reset_password_token]
flash[:alert] = "Url to reset was incorrect, please resend reset email."
redirect_to '/home'
return
end
# there may be a better way of doing this, devise should be able to give us these messages
if params[:user][:password] != params[:user][:password_confirmation]
flash[:alert] = "Passwords must match."
redirect_to :back
return
end
if @user.reset_password!(params[:user][:password],params[:user][:password_confirmation])
@user.hasSetPassword = true
@user.save
respond_to do |format|
format.html { redirect_to '/home', notice: 'Your password has been changed.' }
end
else
flash[:alert] = "Invalid password, must be at least 6 charactors."
redirect_to :back
end
end
def reset_password_edit
@user = User.where(:reset_password_token => params[:reset_password_token]).first
if @user.nil? || !@user.reset_password_period_valid?
flash[:alert] = "Password reset period expired, please resend reset email"
redirect_to "/home"
return
end
end
意見/設計/注冊/編輯; 將視圖更改為不讓用戶編輯需要密碼的字段
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %>
<%= devise_error_messages! %>
<% if !resource.hasSetPassword %>
<%= f.label :name %><br />
<p style="line-height:24px;"><b><%= @user.name %></b></p>
<div><%= f.label :email %><br />
<p style="line-height:24px;"><b><%= @user.email %> </b></p>
<p style="position:relative; left:150px; width:420px;">
<i>you cannot change any settings because you have not set a password <br />yet, you can do so by following the </i>
<%= link_to "Forgot your password", "/users/reset_password" %> <i> procedure</i>
</p>
</div>
<% else %>
<p><%= f.label :name %><br />
<%= f.text_field :name %></p>
<div><%= f.label :email %><br />
<%= f.email_field :email %></div>
<div><%= f.label :password %> <br />
<%= f.password_field :password %><i>(leave blank if you don't want to change it)</i></div>
<div><%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %></div>
<div><%= f.label :current_password %> <br />
<%= f.password_field :current_password %>
<i>(we need your current password to confirm your changes)</i>
</div>
<div><%= f.submit "Update" %></div>
<% end %>
<% end %>
視圖/設計/郵寄者/ reset_password_instructions; 在我們的新案例中,我必須將其更改為指向正確的URL
<p>Hello <%= @resource.email %>!</p>
<p>Someone has requested a link to change your password, and you can do this through the link below.</p>
<% if !@resource.hasSetPassword %>
<p><%= link_to 'Change my password', 'http://streetsbehind.me/users/reset_password_edit?reset_password_token='+@resource.reset_password_token %></p>
<!-- todo: there's probably a better way of doing this than just hardcoding streetsbehind.me -->
<% else %>
<p><%= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @resource.reset_password_token) %></p>
<% end %>
<p>If you didn't request this, please ignore this email.</p>
<p>Your password won't change until you access the link above and create a new one.</p>
意見/用戶/ reset_password_edit.erb
<%= form_for(@user, :url => url_for(:action => :do_reset_password) , :html => { :method => :post }) do |f| %>
<%= f.hidden_field :reset_password_token %>
<div><%= f.label :password, "New password" %><br />
<%= f.password_field :password %></div>
<div><%= f.label :password_confirmation, "Confirm new password" %><br />
<%= f.password_field :password_confirmation %></div>
<div><%= f.submit "Change my password" %></div>
<% end %>
配置/ routes.rb中
get "users/reset_password"
get "users/reset_password_edit"
resource :users do
post 'do_reset_password'
end
我改編了@user3294438 的答案以使其完美適合我。
class PasswordsController < Devise::PasswordsController
# here we need to skip the automatic authentication based on current session for the following four actions
# new : shows the "enter email to reset". need to skip, otherwise it will go directly to root
# create : launches the reset email
# edit: shows the reset password form. need to skip, otherwise it will go directly to root
# update: updates the password, need to skip otherwise it won't even reset if already logged in
skip_before_action :require_no_authentication, :only => [:new, :create, :edit, :update]
# we need to override the update, too.
# After a password is reset, all outstanding sessions are gone.
# When already logged in, sign_in is a no op, so the session will expire, too.
# The solution is to logout and then re-login which will make the session right.
def update
super
if resource.errors.empty?
sign_out(resource_name)
sign_in(resource_name, resource)
end
end
private
# Overriding this method allows to show a nice flash message to the signed-in user that just
# asked for a password reset by email. Otherwise he gets a "you are already signed in" falsh error
def after_sending_reset_password_instructions_path_for(resource_name)
if current_user
flash[:info] = I18n.t "devise.passwords.send_instructions"
return root_path
end
super
end
end
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.