webentwicklung-frage-antwort-db.com.de

Rails 4 + Devise: Beim Zurücksetzen des Passworts wird auf dem Produktionsserver immer ein Fehler "Token ist ungültig" angezeigt, er funktioniert jedoch lokal.

Ich habe eine Rails 4-Anwendung zur Verwendung von Devise eingerichtet, und ich habe ein Problem mit dem Zurücksetzen von Kennwörtern. Ich habe den Mailer eingerichtet, und die E-Mail zum Zurücksetzen des Passworts wird ordnungsgemäß versendet. Dem bereitgestellten Link ist das richtige reset_password_token zugewiesen, das ich mit dieser Datenbank überprüft habe. Wenn ich jedoch das Formular mit korrekt formatierten Kennwörtern übermittle, wird ein Fehler angezeigt, der besagt, dass das Zurücksetzungstoken ungültig ist. 

Derselbe Code funktioniert jedoch lokal über Rails s. Die E-Mail wird gesendet, und ich kann das Kennwort tatsächlich zurücksetzen. Der Code, den ich verwende, ist nur der Standard-Devise-Code. Ich habe keinen davon überschrieben. 

Vielleicht ist es etwas mit Apache? Ich bin nicht so vertraut damit. Hat jemand irgendwelche Ideen? 

47
justindao

Überprüfen Sie den Code in app/views/devise/mailer/reset_password_instructions.html.erb

Der Link sollte generiert werden mit:

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

Wenn Ihre Ansicht diesen Code weiterhin verwendet, ist dies die Ursache des Problems:

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

Devise hat begonnen, Hashes des Tokens zu speichern, daher muss die E-Mail den Link unter Verwendung des realen Tokens (@token) und nicht des in der Datenbank gespeicherten Hash-Werts erstellen.

Diese Änderung erfolgte in Devise in 143794d701

126
doctororange

Wenn Sie resource.find_first_by_auth_conditions überschreiben, müssen Sie zusätzlich zum Fix von doctororange den Fall berücksichtigen, in dem warden_conditions einen reset_password_token anstelle einer E-Mail oder eines Benutzernamens enthält.

EDIT: Um auszuarbeiten:

Devise fügt Ihrem Modell weitere Funktionen hinzu, wenn Sie "devise: registrable,: trackable, ..." sagen. 

In Ihrem Benutzermodell (oder Admin usw.) können Sie die Devise-Methode mit dem Namen find_first_by_auth_conditions überschreiben. Diese spezielle Methode wird von der Devise-Logik zum Suchen des Datensatzes verwendet, bei dem versucht wird, angemeldet zu werden. Devise gibt einige Informationen in einem Parameter namens warden_conditions weiter. Diese enthält eine E-Mail, einen Benutzernamen oder ein reset_password_token oder ein anderes Element, das Sie Ihrem Anmeldeformular für Devise hinzufügen (z. B. eine Konto-ID).

Beispielsweise haben Sie möglicherweise etwas, das folgendermaßen aussieht:

(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

Durch den obigen Code wird jedoch die Funktion zum Zurücksetzen des Kennworts beschädigt, da devise zum Auffinden des Datensatzes ein Token verwendet. Der Benutzer gibt keine E-Mail-Adresse ein. Er gibt das Token über eine Abfragezeichenfolge in der URL ein, die an diese Methode übergeben wird, um den Datensatz zu finden.

Wenn Sie diese spezielle Methode überschreiben, müssen Sie sie daher robuster machen, um den Fall für das Zurücksetzen des Kennworts zu berücksichtigen:

(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
11
MaximusDominus

Wenn Sie die URL aus einem Protokoll entnehmen, kann sie folgendermaßen aussehen:

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

In diesem Fall funktioniert die Verwendung von 3DJ5Z5g6QNVQb3ZXkiKjTx als Token nicht, da =3D wirklich ein =-Zeichen ist.

In diesem Fall müssen Sie J5Z5g6QNVQb3ZXkiKjTx verwenden (wobei 3D entfernt ist).

5
ybart

Obwohl die akzeptierte Antwort korrekt ist, wollte ich erklären, warum dies geschieht, damit Sie sie auch in anderen Fällen verwenden können. Wenn Sie sich die Methode ansehen, mit der das Token zum Zurücksetzen des Kennworts generiert wird:

def set_reset_password_token
    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)
    raw
end

Sie werden sehen, dass das raw zurückgegeben wird und das enc in der Datenbank gespeichert wird. Wenn Sie den Wert aus der Datenbank verwenden - enc, um ihn in ein password_reset_token In einem ausgeblendeten Feld Ihres Formulars steht immer Token invalid, da dies ein verschlüsseltes Token ist. Das, was Sie verwenden sollten, ist das raw Token.

Dies geschah, weil für den Fall, dass ein Administrator (oder ein Hacker) auf die Datenbank zugreifen kann, der Administrator einfach das Kennwort eines anderen Benutzers mithilfe eines verschlüsselten Tokens zurücksetzen kann, was vermieden werden soll.

Einige Informationen zu dieser und einigen anderen Änderungen in Devise finden Sie im Änderungsprotokoll-Blog-Beitrag von Devise oder in der Diskussion über das Thema von Devise

0
Aleks

Wenn Sie eine benutzerdefinierte Bestätigungsmailer-Ansicht verwenden, ist möglicherweise (zusätzlich zu @ doctororanges Post-Ablve) auch Folgendes zu beachten:.

Der Link in der Ansicht hat sich auch hier geändert. Dies ist der NEUE Link-Code:

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

Dies ist der ALTE Link-Code:

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