首页 文章

Rails 4 Devise:密码重置始终在 生产环境 服务器上提供“令牌无效”错误,但在本地工作正常 .

提问于
浏览
47

我有一个Rails 4应用程序设置为使用Devise,我正在运行密码重置问题 . 我有邮件设置,密码重置电子邮件发送正常 . 提供的链接具有分配给它的正确reset_password_token,我使用该数据库检查了该链接 . 但是,当我使用格式正确的密码提交表单时,会出现错误,指出重置令牌无效 .

但是,完全相同的代码在本地通过 rails s 正常工作 . 电子邮件发送,我实际上可以重置密码 . 我使用的代码只是标准的Devise代码,我没有覆盖任何代码 .

也许这与Apache有关?我不太熟悉它 . 有没有人有任何想法?

4 回答

  • 122

    检查 app/views/devise/mailer/reset_password_instructions.html.erb 中的代码

    该链接应生成:

    edit_password_url(@resource, :reset_password_token => @token)

    如果您的视图仍然使用此代码,那么这将是问题的原因:

    edit_password_url(@resource, :reset_password_token => @resource.password_reset_token)

    Devise开始存储令牌的哈希值,因此电子邮件需要使用真实令牌( @token )而不是存储在数据库中的哈希值来创建链接 .

    这个变化发生在143794d701的Devise中

  • 0

    除了docorange 's fix, if you'重写 resource.find_first_by_auth_conditions 之外,您还需要考虑 warden_conditions 包含 reset_password_token 而不是电子邮件或用户名的情况 .

    编辑:详细说明:

    当您说'设计:可注册,可跟踪,......'时,Devise会为您的模型添加功能 .

    在用户模型(或管理员等)中,您可以覆盖名为find_first_by_auth_conditions的Devise方法 . Devise逻辑使用此特殊方法来查找尝试登录的记录 . Devise在一个名为warden_conditions的参数中传递一些信息 . 这将包含电子邮件,用户名或reset_password_token,或您添加到设计登录表单中的任何其他内容(例如帐户ID) .

    例如,您可能会看到如下内容:

    (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
    

    但是,上面的代码将破坏密码重置功能,因为设计使用令牌来定位记录 . 用户不输入电子邮件,他们通过URL中的查询字符串输入令牌,该字符串将传递给此方法以尝试查找记录 .

    因此,当您覆盖此特殊方法时,您需要使其更加健壮以解决密码重置情况:

    (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
    
  • 4

    如果您从日志中获取URL,它可能如下所示:

    web_1      | <p><a href=3D"http://localhost:3000/admin/password/edit?reset_password_to=
    web_1      | ken=3DJ5Z5g6QNVQb3ZXkiKjTx">Change password</a></p>
    

    在这种情况下,使用 3DJ5Z5g6QNVQb3ZXkiKjTx 作为令牌将不起作用,因为 =3D 实际上是一个 = 字符编码 .

    在这种情况下,您需要使用 J5Z5g6QNVQb3ZXkiKjTx (已删除 3D

  • 9

    如果您使用自定义确认邮件程序视图,还可能值得注意(除了@ doctororange的帖子之外)以下内容 .

    视图中的链接也在这里发生了变化 . 这是新的链接代码:

    <p><%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %></p>
    

    这是OLD链接代码:

    <p><%= link_to 'Confirm my account', user_confirmation_url(@resource, :confirmation_token => @resource.confirmation_token) %></p>
    

相关问题