web-dev-qa-db-ja.com

ユーザーがサインアップするときに「確認トークンが無効です」を考案する

Webアプリで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 "[email protected]"                                # 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$
_

このエラーは、Webサーバーから手動でサインアップした場合にも再現可能であるため、Cucumberの問題ではないようです。

をお願いします:

  • ユーザーは、このメールのリンクからアカウントをワンクリックで確認できます
  • アカウントを確認した後、ユーザーがサインインしたままになるようにします

私はセットアップがあります:

  • GitHubからの最新のDeviseコード(3.1.0、ref 041fcf90807df5efded5fdcd53ced80544e7430f)
  • Userを実装するconfirmableクラス
  • 「デフォルト」確認コントローラーの使用(独自のカスタムコントローラーを定義していません。)

私はこれらの投稿を読みました:

そして試してみました:

  • Deviseイニシャライザーで_config.allow_insecure_tokens_lookup = true_を設定すると、起動時に「不明なメソッド」エラーがスローされます。さらに、これは一時的な修正に過ぎないように思われるため、使用を避けたいと思います。
  • DBをパージし、ゼロから開始しました(したがって、古いトークンは存在しません)

更新:

登録後にUserに保存されている確認トークンを確認します。電子メールトークンはDBトークンと一致します。上記の投稿によると、新しいDeviseの動作は想定されていないと述べており、代わりに、電子メールのトークンに基づいて2番目のトークンを生成する必要があります。 これは疑わしいです。User.confirm_by_token('[EMAIL_CONFIRMATION_TOKEN]')を実行すると、エラーセット "@messages = {:confirmation_token => [" is invalid "]}"を持つユーザーが返されます。問題の原因と思われます。

トークンの不一致が問題の核心のようです。コンソールで次のコードを実行して、ユーザーのconfirm_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
_

そもそも間違った確認トークンをDBに保存するのはなぜですか?私はカスタム登録コントローラーを使用しています...多分それが間違って設定される原因となる何かがありますか?

routes.rb

_  devise_for  :users,
          :path => '',
          :path_names => {
            :sign_in => 'login',
            :sign_out => 'logout',
            :sign_up => 'register'
            },
          :controllers => {
            :registrations => "users/registrations",
            :sessions => "users/sessions"
          }
_

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
_
44
David Elner

そのため、Devise 3.1.0にアップグレードすると、しばらく触れなかったビューに「残酷」が残りました。

このブログ投稿 によると、古い@tokenの代わりに@resource.confirmation_tokenを使用するようにDeviseメーラーを変更する必要があります。

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>

これにより、トークンベースの確認の問題が修正されます。これにより、ロック解除やパスワードトークンの問題も修正される可能性があります。

97
David Elner

Devise 3.5.2の時点で、確認トークンは確認プロセス中にダイジェストされなくなりました。これは、電子メール内のトークンがデータベース内のトークンと一致することを意味します。

これを理解した後も確認にまだ問題がありましたが、私の場合は、オーバーロードしたときに導入したバグであることが判明しましたfind_first_by_auth_conditions。その方法で導入したバグを修正することで、確認してエラーを修正しました。

0
Karen

私の友人がこの質問を見つけて、私にこれを理解したかどうか尋ねたところ、私は自分の答えを提出したことがないことを思い出したので、ここに行きます:)

最終的にトークンをリセットし、sendを使用して生のトークンを取得しました。 ugいですが、devise (3.5.1)のパンチで動作します。

26   it "should auto create org" do
27     email = FG.generate :email
28     visit new_user_registration_path
29     fill_in :user_name, with: 'Ryan Angilly'
30     fill_in :user_user_provided_email, with: email
31     fill_in :user_password, with: '1234567890'
32 
33     expect do
34       click_button 'Continue'
35     end.to change { Organization.count }.by(1)
36 
37     expect(page.current_path).to eq(confirmation_required_path)
38     u = User.where(email: email).first
39     u.send :generate_confirmation_token
40     email_token = u.instance_variable_get(:@raw_confirmation_token)
41     u.save!
42     os = u.organizations
43     expect(os.size).to eq(1)
44     visit user_confirmation_path(confirmation_token: email_token)
45     o = os.first
46 
47     u.reload
48     expect(u.confirmed?)
49     expect(page.current_url).to eq(organization_getting_started_url(o))
50   end
0
Ryan Angilly