Rails 4 + Devise: Password Reset is always giving a “Token is invalid” error on the production server, but works fine locally.

后端 未结 5 1523
再見小時候
再見小時候 2020-12-05 04:05

I have a Rails 4 application set up to use Devise, and I\'m running a problem with password resets. I have the mailer set up, and the password reset email sends fine. The li

5条回答
  •  野趣味
    野趣味 (楼主)
    2020-12-05 04:31

    In addition to doctororange's fix, if you're overwriting resource.find_first_by_auth_conditions, you need to account for the case where warden_conditions contains a reset_password_token instead of an email or username.

    EDIT: To elaborate:

    Devise adds functionality to your model when you say 'devise :registerable, :trackable, ...'.

    In your User model (or Admin, etc), you can overwrite the Devise method named find_first_by_auth_conditions. This special method is used by the Devise logic to locate the record that is attempting to be logged in to. Devise passes in some info in a parameter called warden_conditions. This will contain an email, a user-name, or a reset_password_token, or anything else you add to your devise log-in form (such as an account-id).

    For example, you might have something that looks like this:

    (app/models/user.rb)
    class User
    
      ...
    
      def self.find_first_by_auth_conditions warden_conditions
        conditions = warden_conditions.dup
    
        if (email = conditions.delete(:email)).present?
          where(email: email.downcase).first
        end
      end
    
    end
    

    However, The above code will break the password-reset functionality, because devise is using a token to locate the record. The user doesn't enter an email, they enter the token via a query-string in the URL, which gets passed to this method to try and find the record.

    Therefore, when you overwrite this special method you need to make it more robust to account for the password-reset case:

    (app/models/user.rb)
    class User
    
      ...
    
      def self.find_first_by_auth_conditions warden_conditions
        conditions = warden_conditions.dup
    
        if (email = conditions.delete(:email)).present?
          where(email: email.downcase).first
        elsif conditions.has_key?(:reset_password_token)
          where(reset_password_token: conditions[:reset_password_token]).first
        end
      end
    
    end
    

提交回复
热议问题