【问题标题】:Upgrading to devise 3.1 => getting Reset password token is invalid升级到设计 3.1 => 获取重置密码令牌无效
【发布时间】:2013-09-06 15:47:51
【问题描述】:

解决方案

感谢gist Steven Harman 的表格,我得到了它的工作。 devise_mail_helpers.rb

module Features
  module MailHelpers

    def last_email
      ActionMailer::Base.deliveries[0]
    end

    # Can be used like:
    #  extract_token_from_email(:reset_password)
    def extract_token_from_email(token_name)
      mail_body = last_email.body.to_s
      mail_body[/#{token_name.to_s}_token=([^"]+)/, 1]
    end

  end
end

我将文件devise_mail_helpers.rb 添加到与功能规范相同的文件夹中并编写了此规范。

require 'devise_mail_helpers.rb'
include Features
include MailHelpers
describe "PasswordResets" do
  it "emails user when requesting password reset" do
    user = FactoryGirl.create(:user)
    visit root_url
    find("#login_link").click
    click_link "Forgot your password?"
    fill_in "Email", :with => user.email
    click_button "Send instructions"
    current_path.should eq('/users/sign_in')
    page.should have_content("You will receive an email with instructions about how to reset your password in a few minutes.")
    last_email.to.should include(user.email)
    token = extract_token_from_email(:reset_password) # Here I call the MailHelper form above
    visit edit_password_url(reset_password_token: token)
    fill_in "user_password", :with => "foobar"
    fill_in "user_password_confirmation", :with => "foobar1"
    find('.signup_firm').find(".submit").click
    page.should have_content("Password confirmation doesn't match Password")
  end
 end

这需要注意规范,以使其在浏览器中工作,请查看下面 Dave 的答案。

原始问题

在我的 rails 4 应用程序中,我已将 devise 升级到 3.1 并运行 rails s,然后我得到了这个:

`raise_no_secret_key': Devise.secret_key was not set. 
 Please add the following to your Devise initializer: (RuntimeError)
 config.secret_key = '--secret--'

我将密钥添加到设计初始化程序中。

在此之后,当我尝试重置密码时出现以下错误

Reset password token is invalid

电子邮件中发送的令牌似乎不正确。其他一切都在工作。我登录和退出就像一把温热的刀槽黄油。

更新

现在我猜它必须与reset_password_token 的加密有关,这里来自功能规范:

user = FactoryGirl.create(:user, 
 :reset_password_token => "something", 
 :reset_password_sent_at => 1.hour.ago)
visit edit_password_url(user, :reset_password_token => 
  user.reset_password_token)
fill_in "user_password", :with => "foobar"
click_button "Change my password"
page.should have_content("Password confirmation doesn't match Password")

发生的错误是:

Failure/Error: page.should have_content
("Password confirmation doesn't match Password")        
expected to find text "Password confirmation doesn't match Password" in 
"Reset password token is invalid"

关于我缺少什么的任何想法?

【问题讨论】:

    标签: ruby-on-rails devise ruby-on-rails-4 factory-bot rspec2


    【解决方案1】:

    您不久前评论了my similar question,我找到了一个可能对您也有帮助的答案。

    升级到 Devise 3.1.0 在视图中留下了一些我有一段时间没有触及的“粗糙”。根据this blog post,您需要更改您的设计邮件以使用@token 而不是旧的@resource.confirmation_token

    app/views/<user>/mailer/reset_password_instructions.html.erb 中找到它并将其更改为:

    <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>
    <p><%= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @token) %></p>
    <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>
    

    这应该可以解决您遇到的任何基于令牌的确认问题。这也可能解决任何解锁或确认令牌问题。

    【讨论】:

    • 这是让它在浏览器上工作的正确解决方案,但如何测试呢?
    • 一目了然,您上面的 Rspec 测试看起来应该可以解决问题。假设“无效令牌”问题消失了,如果它在特定位置失败,您应该分享错误。从战略上讲,将 Rspec 或 Cucumber 与 email_spec 结合起来应该可以让您自动测试它。我的链接问题和this wiki 有更多关于如何用 Cucumber 测试设计的信息。
    • 测试通过了。在我解决问题之前,它因“无效令牌”而失败。
    • 如果您使用自定义邮件程序,您必须通过 def reset_password_instructions(user, token, opts={}) @token = token ..... 向视图提供令牌
    【解决方案2】:

    仅供参考,如果您尝试通过其他方式(即不同的邮件程序)发送重置密码令牌,您可以在您的 User 类中使用这样的代码(从 Devise 源代码中挖出):

    def send_invitation
      raw, enc = Devise.token_generator.generate(self.class, :reset_password_token)
    
      self.reset_password_token   = enc
      self.reset_password_sent_at = Time.now.utc
      self.save(:validate => false)
    
      Notifier.signup_notification(contactable: self, token: raw).deliver
    end
    

    【讨论】:

    • 密钥是self.reset_password_token = enc,设置@token = raw。非常感谢~!
    【解决方案3】:

    我猜你已经将 Devise 升级到 v3.1 而不是 v3.01,因为 config.secret_key。所以我认为它与新的设计功能 - 密钥有关。
    我发现了两个有助于更好理解的密钥功能提交: https://github.com/plataformatec/devise/commit/32648027e282eb4c0f4f42e9c9cc0c961765faa8 https://github.com/plataformatec/devise/commit/d56641f514f54da04f778b2a9b816561df7910c2

    您可能还会在http://blog.plataformatec.com.br/2013/08/devise-3-1-now-with-more-secure-defaults/ 上找到对您有用的东西。
    您也可以在https://github.com/plataformatec/devise/compare/v3.0...v3.1.0 上grep reset_password_token

    编辑
    继续阅读http://blog.plataformatec.com.br/2013/08/devise-3-1-now-with-more-secure-defaults/

    • 现在,Devise 邮件程序会收到一个额外的令牌参数 方法。如果您已自定义设计邮件程序,则必须 更新它。 所有邮件视图也需要更新才能使用 @token,如图here,而不是直接从 资源;

    【讨论】:

    • 谢谢!我已经调查了更多。我知道 Devise 中令牌处理的变化。所以,我必须在浏览器中工作。但是,如何测试呢?在blog的评论中有一些提示。顺便把3.01的错字改成了3.1。
    【解决方案4】:

    我在规格上遇到了这个错误。我试图在用户上手动设置reset_password_token,这样我就可以将令牌传递给edit_user_password_path。但是,重置令牌是散列的,因此手动设置它不起作用。哎呀!为避免此错误,我将reset_token 设置为等于user.send_reset_password_instructions 返回的实际生成的令牌。

    工作规格:

    require 'spec_helper'
    
    feature 'User resets password' do
      scenario 'fills out reset form' do
        user = create(:user)
        reset_token = user.send_reset_password_instructions
        new_password = 'newpassword!'
        visit edit_user_password_path(user, reset_password_token: reset_token)
    
        fill_in :user_password, with: new_password
        fill_in :user_password_confirmation, with: new_password
        click_button 'Change my password'
    
        expect(page).to have_content(
          'Your password was changed successfully. You are now signed in.'
        )
      end
    end
    

    【讨论】:

      【解决方案5】:

      正如其他人所说:原因是生成包含重置密码链接的邮件的视图需要更改。

      我看到这个错误是因为我仍在使用devise-i18n-views gem,它会生成旧链接。删除该 gem 并依赖现在是 devise-i18n gem 一部分的视图为我解决了这个问题。

      【讨论】:

        【解决方案6】:

        在您的设计重置密码模板中确保以下内容正确:

        =link_to '更改我的密码', edit_password_url(@resource, :reset_password_token => @token)

        【讨论】:

          猜你喜欢
          • 2013-09-30
          • 2016-02-22
          • 1970-01-01
          • 1970-01-01
          • 2015-02-21
          • 2021-08-11
          • 2018-09-30
          • 1970-01-01
          • 2016-05-03
          相关资源
          最近更新 更多