8

Tôi đang tự hỏi nếu có một cách gọi 'quên mật khẩu' thủ tục mà không buộc người dùng của tôi để đăng xuấtlập mưu Quên mật khẩu cho người dùng đăng nhập

Trường hợp Tôi đang chạy vào là: 1. người dùng đăng nhập bằng facebook, mật khẩu giả được tạo cho họ 2. người dùng sau đó muốn thay đổi email/tên/mật khẩu của họ hoặc chỉ sử dụng thông tin đăng nhập không facebook

vì cần có mật khẩu để thay đổi các trường này, như nó phải, người dùng không thể sửa đổi chúng

Tôi đã nghĩ về việc không phải là forc để đặt mật khẩu nhưng điều đó không có ý nghĩa bảo mật vì vậy thay vào đó tôi chỉ hiển thị các trường dưới dạng văn bản và thông báo cho người dùng làm theo quy trình 'quên mật khẩu' để đặt mật khẩu và sau đó họ có thể thay đổi các trường

vấn đề sau đó là tôi không thể chỉ đơn giản là liên kết đến đây từ hồ sơ người dùng kể từ devise sẽ cho người dùng rằng họ không thể làm điều này trong khi đã đăng nhập.

Vậy là có một cách của trọng mật khẩu quên hoặc/người dùng/mật khẩu/phương pháp chỉnh sửa để người dùng đã đăng nhập cũng có thể thực hiện hành động này?

Trả lời

2

Giải pháp hoàn chỉnh của tôi ở đây, vì sau đó tôi cũng biết rằng người dùng sẽ phải đăng xuất sau khi nhấp vào liên kết trong email, thêm một số hành động UserController bổ sung để thực sự chỉnh sửa mật khẩu cũng như lưu mật khẩu. Đây không phải là một giải pháp lý tưởng và lạnh lẽo có thể được thực hiện một cách tốt hơn nhưng nó làm việc cho tôi.

bộ điều khiển người dùng; các phương thức được thêm để thực hiện đặt lại

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? || [email protected]_password_period_valid? 
      flash[:alert] = "Password reset period expired, please resend reset email" 
      redirect_to "/home" 
      return 
     end 
    end 

lượt xem/lập/đăng ký/chỉnh sửa; đã thay đổi chế độ xem để không cho phép người dùng chỉnh sửa các trường yêu cầu mật khẩu

<%= 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", "https://stackoverflow.com/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 %> 

lượt xem/devise/mailer/reset_password_instructions; đã phải thay đổi nó để trỏ đến URL đúng trong trường hợp của chúng tôi mới

<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 [email protected] %> 
     <p><%= link_to 'Change my password', 'http://streetsbehind.me/users/reset_password_edit?reset_password_token='[email protected]_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> 

views/người dùng/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 %> 

config/routes.rb

get "users/reset_password" 
get "users/reset_password_edit" 

resource :users do 
    post 'do_reset_password' 
end 
4

Bạn có thể sử dụng @user.send_reset_password_instructions để tạo mã thông báo đặt lại mật khẩu và gửi email. Nếu bạn chỉ gọi trực tiếp cho người gửi thư, mã thông báo đặt lại mật khẩu sẽ không được tạo để xác thực đặt lại.

+0

Điều đó đã làm việc tốt hơn rất nhiều. – fiestacasey

15

Lý do mà bạn không thể đặt lại mật khẩu là do người cố gắng cố gắng xác thực người dùng với phiên hiện tại và khi thành công, bạn sẽ tự động được chuyển hướng đến bất kỳ đường dẫn nào mà nó được yêu cầu truy cập. Những gì bạn cần là ghi đè lên chỉnh sửa và cập nhật hành động của bộ điều khiển mật khẩu để làm cho nó bỏ qua bước này.

Đây là mã. Trong bộ điều khiển mật khẩu của bạn thêm các mã sau đây (bạn có thể yêu cầu tạo ra các bộ điều khiển cho bạn, hoặc bạn chỉ có thể tạo bộ điều khiển sau đây). Ghi đè để cập nhật là cần thiết vì nếu không, người dùng đã đăng nhập sẽ tự động đăng xuất sau khi đặt lại mật khẩu của bạn.(Hoặc nếu bạn muốn nó được như thế bạn có thể thoát khỏi sự đè #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 

Các đường bay như sau

# config/routes.rb 
devise_for :users, :controllers => {:passwords => 'passwords'} 
Các vấn đề liên quan