Подтвердить что ты не робот

Rails 4 + Devise: пароль Reset всегда дает ошибку "токен недействителен" на рабочем сервере, но работает нормально локально.

У меня есть приложение Rails 4, настроенное для использования Devise, и у меня проблема с сбросом пароля. У меня установлена ​​почтовая рассылка, и пароль reset отправляет сообщения. Предоставленная ссылка имеет правильный reset_password_token, назначенный ей, который я проверил с этой базой данных. Однако, когда я отправляю форму с правильно отформатированными паролями, она дает ошибку, заявляющую, что токен reset недействителен.

Однако, тот же самый код работает нормально локально через rails s. Письмо отправляется, и я действительно могу reset пароль. Код, который я использую, является стандартным кодом Devise, я его не отменял.

Возможно, это что-то с Apache? Я не слишком хорошо знаком с этим. У кого-нибудь есть идеи?

4b9b3361

Ответ 1

Проверьте код в app/views/devise/mailer/reset_password_instructions.html.erb

Ссылка должна быть сгенерирована с помощью:

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

Если ваше мнение по-прежнему использует этот код, это станет причиной проблемы:

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

Утилита начала хранить хэши маркера, поэтому электронной почте необходимо создать ссылку, используя реальный токен (@token), а не хешированное значение, хранящееся в базе данных.

Это изменение произошло в Devise в 143794d701

Ответ 2

В дополнение к fixorange fix, если вы перезаписываете resource.find_first_by_auth_conditions, вам нужно учитывать случай, когда warden_conditions содержит reset_password_token вместо имени или имени пользователя.

РЕДАКТИРОВАТЬ: Разработать:

Devise добавляет функциональность вашей модели, когда вы говорите "devise: registerable,: trackable,...".

В вашей модели пользователя (или Admin и т.д.) вы можете перезаписать метод разработки с именем find_first_by_auth_conditions. Этот специальный метод используется логикой Devise для поиска записи, в которую пытается войти. Devise передает некоторую информацию в параметре warden_conditions. Это будет содержать адрес электронной почты, имя пользователя или reset_password_token или что-нибудь еще, что вы добавите в свою форму регистрации (например, идентификатор учетной записи).

Например, у вас может быть что-то похожее на это:

(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

Однако приведенный выше код нарушит функциональность password- reset, потому что в разработке используется токен, чтобы найти запись. Пользователь не вводит адрес электронной почты, он вводит токен через строку запроса в URL-адресе, который передается этому методу, чтобы попытаться найти запись.

Поэтому, когда вы перезаписываете этот специальный метод, вам нужно сделать его более надежным для учета пароля - reset case:

(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

Ответ 3

Если вы берете URL из журнала, он может выглядеть следующим образом:

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

В этом случае использование 3DJ5Z5g6QNVQb3ZXkiKjTx в качестве токена не будет работать, потому что =3D действительно кодируется символом =.

В этом случае вам нужно использовать J5Z5g6QNVQb3ZXkiKjTx (с удалением 3D)

Ответ 4

Также можно отметить (в дополнение к @doctororange post ablve) следующее, если вы используете настраиваемое окно просмотра почтовой программы.

Здесь также изменилась ссылка в представлении. Это НОВЫЙ код ссылки:

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

Это код ссылки OLD:

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

Ответ 5

Хотя принятый ответ является правильным, я хотел объяснить, почему это происходит, поэтому вы можете использовать его и в некоторых других случаях. Если вы посмотрите на метод, который генерирует маркер сброса пароля:

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

Вы увидите, что raw возвращается, а enc сохраняется в базе данных. Если вы используете значение из базы данных - enc для помещения в password_reset_token в скрытом поле вашей формы, то он всегда будет Token invalid что токен Token invalid поскольку это зашифрованный токен. Тот, который вы должны использовать, является raw токеном.

Это было сделано потому, что в случае, если какой-либо администратор (или хакер) может получить доступ к базе данных, администратор может легко сбросить любой пароль, просто используя зашифрованный токен, чего следует избегать.

Некоторую информацию об этом и некоторых других изменениях в Devise можно найти в блоге журнала изменений устройства.