用户注册时设计"确认令牌无效"

Dav*_*ner 44 ruby-on-rails devise devise-confirmable

在我的网络应用程序上使用Rails 4和Devise 3.1.0.我写了一个Cucumber测试来测试用户注册; 从电子邮件中单击"确认我的帐户"链接时失败.

Scenario: User signs up with valid data                                                           # features/users/sign_up.feature:9
    When I sign up with valid user data                                                             # features/step_definitions/user_steps.rb:87
    Then I should receive an email                                                                  # features/step_definitions/email_steps.rb:51
    When I open the email                                                                           # features/step_definitions/email_steps.rb:76
    Then I should see the email delivered from "no-reply@mysite.com"                                # features/step_definitions/email_steps.rb:116
    And I should see "You can confirm your account email through the link below:" in the email body # features/step_definitions/email_steps.rb:108
    When I follow "Confirm my account" in the email                                                 # features/step_definitions/email_steps.rb:178
    Then I should be signed in                                                                      # features/step_definitions/user_steps.rb:142
      expected to find text "Logout" in "...Confirmation token is invalid..." (RSpec::Expectations::ExpectationNotMetError)
     ./features/step_definitions/user_steps.rb:143:in `/^I should be signed in$
Run Code Online (Sandbox Code Playgroud)

当我通过Web服务器手动注册时,此错误也是可重现的,因此它似乎不是黄瓜问题.

我想要:

  • 用户只需单击一下即可通过此电子邮件的链接确认其帐户
  • 让用户在确认帐户后保持登录状态

我有设置:

  • 最新的Devise代码,来自GitHub(3.1.0,ref 041fcf90807df5efded5fdcd53ced80544e7430f)
  • User实现的类confirmable
  • 使用'默认'确认控制器(我没有定义自己的自定义控制器.)

我看过这些帖子:

并尝试过:

  • config.allow_insecure_tokens_lookup = true在我的Devise初始化程序中进行设置,在启动时抛出"未知方法"错误.另外,听起来这只是一个临时修复,所以我想避免使用它.
  • 清除我的数据库并从头开始(所以没有旧的令牌存在)

更新:

检查User注册后存储的确认令牌.电子邮件令牌与DB令牌匹配.根据上面的帖子,新的Devise行为说不应该,而是应该根据电子邮件的令牌生成第二个令牌.这是可疑的.运行User.confirm_by_token('[EMAIL_CONFIRMATION_TOKEN]')返回错误设置为"@messages = {:confirmation_token => ["无效"]}"的用户,这似乎是问题的根源.

不匹配的令牌似乎是问题的核心; 在控制台中运行以下代码以手动更改用户的confirmation_token导致确认成功:

new_token = Devise.token_generator.digest(User, :confirmation_token, '[EMAIL_TOKEN]')
u = User.first
u.confirmation_token = new_token
u.save
User.confirm_by_token('[EMAIL_TOKEN]') # Succeeds
Run Code Online (Sandbox Code Playgroud)

那么为什么它首先将错误的确认令牌保存到数据库中呢?我正在使用自定义注册控制器...也许有一些东西导致它被错误地设置?

的routes.rb

  devise_for  :users,
          :path => '',
          :path_names => {
            :sign_in => 'login',
            :sign_out => 'logout',
            :sign_up => 'register'
            },
          :controllers => {
            :registrations => "users/registrations",
            :sessions => "users/sessions"
          }
Run Code Online (Sandbox Code Playgroud)

users/registrations_controller.rb:

class Users::RegistrationsController < Devise::RegistrationsController

  def create
    # Custom code to fix DateTime issue
    Utils::convert_params_date_select params[:user][:profile_attributes], :birthday, nil, true

    super
  end

  def sign_up_params
    # TODO: Still need to fix this. Strong parameters with nested attributes not working.
    #       Permitting all is a security hazard.
    params.require(:user).permit!
    #params.require(:user).permit(:email, :password, :password_confirmation, :profile_attributes)
  end
  private :sign_up_params
end
Run Code Online (Sandbox Code Playgroud)

Dav*_*ner 97

因此,升级到Devise 3.1.0会让我有些"残缺",因为我有一段时间没有触及过.

根据这篇博客文章,您需要更改您的Devise邮件使用@token而不是旧邮件@resource.confirmation_token.

找到这个app/views/<user>/mailer/confirmation_instructions.html.erb并将其更改为:

<p>Welcome <%= @resource.email %>!</p>
<p>You can confirm your account email through the link below:</p>
<p><%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @token) %></p>
Run Code Online (Sandbox Code Playgroud)

这应该可以解决您遇到的任何基于令牌的确认问题.这可能会修复任何解锁或重置密码令牌问题.

  • 谢谢,@戴夫!密码重置模板也是如此.更改为"link_to"更改我的密码',edit_password_url(@resource,reset_password_token:@token)` (7认同)
  • ...对于`unlock_instructions.html`模板也是如此 (2认同)