web-dev-qa-db-fra.com

Devise "Le jeton de confirmation n'est pas valide" lorsque l'utilisateur se connecte

Utilisation de Rails 4 et de Devise 3.1.0 sur mon application Web. J'ai écrit un test de concombre pour tester l'inscription de l'utilisateur; il échoue lorsque vous cliquez sur le lien "confirmer mon compte" à partir de l'e-mail.

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$

Cette erreur est reproductible lorsque je m'inscris manuellement via le serveur Web également, de sorte que cela ne semble pas être un problème lié au concombre.

J'aimerais:

  • L'utilisateur doit pouvoir confirmer en un clic son compte via le lien de ce courrier électronique.
  • Demander à l'utilisateur de rester connecté après avoir confirmé son compte

J'ai mis en place:

  • Le dernier code Devise, de GitHub (3.1.0, réf 041fcf90807df5efded5fdcd53ced80544e7430f)
  • Une classe User qui implémente confirmable
  • Utilisation du contrôleur de confirmation 'par défaut' (je n'ai pas défini mon propre contrôleur personnalisé.)

J'ai lu ces posts:

Et ont essayé:

  • La définition de config.allow_insecure_tokens_lookup = true dans mon initialiseur Devise, qui génère une erreur de "méthode inconnue" au démarrage. De plus, il semble que cela ne soit supposé être qu'une solution temporaire, je voudrais donc éviter de l'utiliser.
  • Purge ma base de données et recommence à zéro (donc aucun ancien jeton n'est présent)

Mettre à jour:

Vérification du jeton de confirmation stocké dans la variable User après l’enregistrement. Le jeton de courrier électronique correspond au jeton de base de données. Selon les articles ci-dessus, le nouveau comportement de Devise indique qu'il n'est pas censé le faire, mais qu'il devrait plutôt générer un deuxième jeton basé sur le jeton de l'e-mail. Ceci est suspect.} _ La fonction User.confirm_by_token('[EMAIL_CONFIRMATION_TOKEN]') renvoie un utilisateur qui a des erreurs, définissez "@ messages = =: confirmation_token => [" n'est pas valide "]}", qui semble être la source du problème.

Le désaccord des jetons semble être au cœur du problème; L'exécution du code suivant dans la console pour modifier manuellement le code de confirmation de l'utilisateur entraîne la confirmation:

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

Alors, pourquoi enregistre-t-il le mauvais jeton de confirmation dans la base de données? J'utilise un contrôleur d'enregistrement personnalisé ... peut-être qu'il contient quelque chose qui le rend incorrect?

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

La mise à niveau vers Devise 3.1.0 a donc laissé un peu de crédibilité dans une vue que je n'avais pas touchée depuis un moment.

Selon cet article de blog , vous devez changer votre logiciel de messagerie Devise pour utiliser @token au lieu de l'ancien @resource.confirmation_token.

Trouvez ceci dans app/views/<user>/mailer/confirmation_instructions.html.erb et changez-le en quelque chose comme:

<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>

Cela devrait résoudre les problèmes de confirmation liés aux jetons que vous rencontrez. Cela corrigera probablement également les problèmes de jeton de mot de passe de déverrouillage ou de réinitialisation.

96
David Elner

À partir de la version 3.5.2, le jeton de confirmation n'est plus digéré pendant le processus de confirmation. Cela signifie que le jeton contenu dans l'e-mail correspondra à celui de la base de données.

J'avais toujours des problèmes avec les confirmations après avoir découvert cela, mais dans mon cas, c'est un bogue que j'ai introduit lorsque j'ai surchargé find_first_by_auth_conditions. En corrigeant le bogue que j'ai introduit dans cette méthode, j'ai corrigé mes erreurs avec confirmation.

0
Karen

Un ami à moi vient de trouver cette question et m'a envoyé un e-mail me demandant si j'avais trouvé cette information, ce qui m'a rappelé que je n'avais jamais soumis ma propre réponse, alors voilà :)

J'ai fini par réinitialiser le jeton et utiliser send pour obtenir le jeton brut. C'est moche, mais ça marche dans un punch pour 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