module ActiveRecord::SignedId::ClassMethods
Открытые методы экземпляра
# File activerecord/lib/active_record/signed_id.rb, line 68
def find_signed(signed_id, purpose: nil, on_rotation: nil)
raise UnknownPrimaryKey.new(self) if primary_key.nil?
options = { on_rotation: on_rotation }.compact
if id = signed_id_verifier.verified(signed_id, purpose: combine_signed_id_purposes(purpose), **options)
find_by primary_key => id
end
end Позволяет найти запись по подписанному идентификатору, который безопасно публиковать, не опасаясь подделки. Это особенно полезно для таких задач, как сброс пароля или подтверждение адреса электронной почты: вы хотите, чтобы обладатель подписанного идентификатора мог взаимодействовать с соответствующей записью, но обычно только в течение определённого периода времени.
Период действия подписанного идентификатора задаётся при его создании с помощью метода экземпляра signed_id(expires_in: 15.minutes). Если до попытки поиска по подписанному идентификатору срок действия истёк, идентификатор становится недействительным, и возвращается nil.
Использование подписанного идентификатора можно дополнительно ограничить, указав назначение. Это полезно, если у вас есть общая базовая модель, например User, для которой могут создаваться подписанные идентификаторы для разных целей, таких как сброс пароля или подтверждение адреса электронной почты. Назначение, заданное при создании идентификатора, должно совпадать с назначением, указанным при поиске. Если они не совпадают, снова возвращается nil.
Примеры
signed_id = User.first.signed_id expires_in: 15.minutes, purpose: :password_reset User.find_signed signed_id # => nil, since the purpose does not match travel 16.minutes User.find_signed signed_id, purpose: :password_reset # => nil, since the signed id has expired travel_back User.find_signed signed_id, purpose: :password_reset # => User.first
# File activerecord/lib/active_record/signed_id.rb, line 89
def find_signed!(signed_id, purpose: nil, on_rotation: nil)
options = { on_rotation: on_rotation }.compact
if id = signed_id_verifier.verify(signed_id, purpose: combine_signed_id_purposes(purpose), **options)
find(id)
end
end Работает как find_signed, но вызывает исключение ActiveSupport::MessageVerifier::InvalidSignature, если срок действия signed_id истёк, назначение не совпадает, идентификатор относится к другой записи или был подделан. Также вызывает исключение ActiveRecord::RecordNotFound, если по действительному подписанному идентификатору не удаётся найти запись.
Примеры
User.find_signed! "bad data" # => ActiveSupport::MessageVerifier::InvalidSignature signed_id = User.first.signed_id User.first.destroy User.find_signed! signed_id # => ActiveRecord::RecordNotFound
# File activerecord/lib/active_record/signed_id.rb, line 96
def signed_id_verifier
if signed_id_verifier_secret
@signed_id_verifier ||= begin
secret = signed_id_verifier_secret
secret = secret.call if secret.respond_to?(:call)
if secret.nil?
raise ArgumentError, "You must set ActiveRecord::Base.signed_id_verifier_secret to use signed IDs"
end
ActiveSupport::MessageVerifier.new secret, digest: "SHA256", serializer: JSON, url_safe: true
end
else
return _signed_id_verifier if _signed_id_verifier
if ActiveRecord.message_verifiers.nil?
raise "You must set ActiveRecord.message_verifiers to use signed IDs"
end
ActiveRecord.message_verifiers["active_record/signed_id"]
end
end # File activerecord/lib/active_record/signed_id.rb, line 122
def signed_id_verifier=(verifier)
if signed_id_verifier_secret
@signed_id_verifier = verifier
else
self._signed_id_verifier = verifier
end
end Позволяет передать пользовательский верификатор для подписанных идентификаторов. Это также позволяет использовать разные верификаторы для разных классов. Это полезно и при необходимости сменить ключи: пользовательский верификатор можно заранее подготовить к этому. Подробности см. в документации ActiveSupport::MessageVerifier.
© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.