2016-07-02 4 views
1

Когда ссылка на сброс пароля отправляется по электронной почте, она, похоже, не работает. При нажатии на нее приводит к перенаправлять на домашнюю страницу из-за:Michael Hartl Chap 12 Password Reset перенаправляет на домашнюю страницу

фильтр цепь остановлена, как: valid_user оказаны или перенаправлены

Здесь valid_user

# Confirms a valid user. 
    def valid_user 
     unless (@user && @user.activated? && 
       @user.authenticated?(:reset, params[:id])) 
     redirect_to root_url 
     end 
    end 

PasswordsResetsController

class PasswordResetsController < ApplicationController 
    before_action :get_user,   only: [:edit, :update] 
    before_action :valid_user,  only: [:edit, :update] 
    before_action :check_expiration, only: [:edit, :update] # Case (1) 

    def new 
    end 

    def create 
    @user = User.find_by(email: params[:password_reset][:email].downcase) 
    if @user 
     @user.create_reset_digest 
     @user.send_password_reset_email 
     flash[:info] = "Email sent with password reset instructions" 
     redirect_to root_url 
    else 
     flash.now[:danger] = "Email address not found" 
     render 'new' 
    end 
    end 

    def edit 
    end 

    def update 
    if params[:user][:password].empty?     # Case (3) 
     @user.errors.add(:password, "can't be empty") 
     render 'edit' 
    elsif @user.update_attributes(user_params)   # Case (4) 
     log_in @user 
     flash[:success] = "Password has been reset." 
     redirect_to @user 
    else 
     render 'edit'          # Case (2) 
    end 
    end 

    private 

    def user_params 
     params.require(:user).permit(:password, :password_confirmation) 
    end 

    # Before filters 

    def get_user 
     @user = User.find_by(email: params[:email]) 
    end 

    # Confirms a valid user. 
    def valid_user 
     unless (@user && @user.activated? && 
       @user.authenticated?(:reset, params[:id])) 
     redirect_to root_url 
     end 
    end 

    # Checks expiration of reset token. 
    def check_expiration 
     if @user.password_reset_expired? 
     flash[:danger] = "Password reset has expired." 
     redirect_to new_password_reset_url 
     end 
    end 
end 

User.rb

class User < ActiveRecord::Base 
    attr_accessor :remember_token, :activation_token, :reset_token 
    before_save :downcase_email 
    before_create :create_activation_digest 
    validates :name, presence: true, length: { maximum: 50 } 
    VALID_EMAIL_REGEX = /\A[\w+\-.][email protected][a-z\d\-.]+\.[a-z]+\z/i 
    validates :email, presence: true, length: { maximum: 255 }, 
        format: { with: VALID_EMAIL_REGEX }, 
        uniqueness: { case_sensitive: false } 
    validates :username, presence: true, length: { maximum: 50 } 
    has_secure_password 
    validates :password, presence: true, length: { minimum: 6 }, allow_nil: true 

    # Returns the hash digest of the given string. 
    def User.digest(string) 
    cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : 
                BCrypt::Engine.cost 
    BCrypt::Password.create(string, cost: cost) 
    end 

    # Returns a random token. 
    def User.new_token 
    SecureRandom.urlsafe_base64 
    end 

    # Remembers a user in the database for use in persistent sessions. 
    def remember 
    self.remember_token = User.new_token 
    update_attribute(:remember_digest, User.digest(remember_token)) 
    end 

    # Returns true if the given token matches the digest. 
    def authenticated?(attribute, token) 
    digest = send("#{attribute}_digest") 
    return false if digest.nil? 
    BCrypt::Password.new(digest).is_password?(token) 
    end 

    # Forgets a user. 
    def forget 
    update_attribute(:remember_digest, nil) 
    end 

    # Activates an account. 
    def activate 
    update_attribute(:activated, true) 
    update_attribute(:activated_at, Time.zone.now) 
    end 

    # Sends activation email. 
    def send_activation_email 
    UserMailer.account_activation(self).deliver_now 
    end 

    # Sets the password reset attributes. 
    def create_reset_digest 
    self.reset_token = User.new_token 
    update_attribute(:reset_digest, User.digest(reset_token)) 
    update_attribute(:reset_sent_at, Time.zone.now) 
    end 

    # Sends password reset email. 
    def send_password_reset_email 
    UserMailer.password_reset(self).deliver_now 
    end 

    # Returns true if a password reset has expired. 
    def password_reset_expired? 
    reset_sent_at < 2.hours.ago 
    end 

    private 

    # Converts email to all lower-case. 
    def downcase_email 
    self.email = email.downcase 
    end 

    # Creates and assigns the activation token and digest. 
    def create_activation_digest 
    self.activation_token = User.new_token 
    self.activation_digest = User.digest(activation_token) 
    end 

end 

Я не могу понять, почему он это делает. Когда я удаляю аутентификацию? часть кода в методе valid_user, он по-прежнему перенаправляется на домашнюю страницу.

ответ

2

Проблема заключалась в том, что я тестировал это с использованием пользователя, которого я создал, и не прошел метод «активации» из-за того, как я создал пользователя. Я тестировал с пользователем, проходящим процесс регистрации на веб-сайте, и он работает.

+0

Рад, что вы смогли решить проблему. Подумайте о принятии своего собственного ответа: http://meta.stackexchange.com/a/5235/249307 – SoAwesomeMan

1

Я предполагаю, что у вас есть before_filter :valid_user в вашем application_controller.rb. Если это так, попробуйте добавить условие к valid_user, которое предотвращает проверку подлинности и активацию. Например, можно настроить следующий метод в соответствии с вашими потребностями:

def valid_user 
    unless controller_name == "password_resets" 
    unless (@user && @user.activated? && 
      @user.authenticated?(:reset, params[:id])) 
     redirect_to root_url 
    end 
    end 
end 

Если у вас есть before_filter :valid_user в вашем password_resets_controller.rb, вы можете просто удалить его, так как случай использования включает в себя: пользователь не будет проверяться при попытке сбросьте свой пароль.

+1

Это похоже на хорошее обходное решение. Я чувствую, что с этим что-то не хватает. Разве это не привело бы к недостатку безопасности? И не должен ли он быть аутентифицирован, потому что токен сброса соответствует дайджесту? – Doughtz

+0

Хорошие вопросы. Я ничего не читал от Хартла и не думал, что токен был чем-то иным, чем идентификатором. Использование чего-то вроде JWT для токена сброса является умным. – SoAwesomeMan

Смежные вопросы