跳到内容 跳到搜索
方法
F
S

实例公开方法

find_signed(signed_id, purpose: nil)

允许您根据签名 ID 查找记录,该签名 ID 安全地放在世界中,无需担心篡改。这对于密码重置或电子邮件验证等情况特别有用,您希望签名 ID 的持有者能够与基础记录进行交互,但通常只在特定时间段内进行。

您在生成期间使用实例方法 signed_id(expires_in: 15.minutes) 设置签名 ID 有效的时间段。如果在尝试签名查找之前时间已过,则签名 ID 将不再有效,并且会返回 nil。

可以使用目的进一步限制签名 ID 的使用。当您有一个通用基本模型(例如 User)时,这很有帮助,该模型可能对多个事物(例如密码重置或电子邮件验证)具有签名 ID。生成期间设置的目的必须与查找期间设置的目的匹配。如果存在不匹配,则再次返回 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 52
def find_signed(signed_id, purpose: nil)
  raise UnknownPrimaryKey.new(self) if primary_key.nil?

  if id = signed_id_verifier.verified(signed_id, purpose: combine_signed_id_purposes(purpose))
    find_by primary_key => id
  end
end

find_signed!(signed_id, purpose: nil)

find_signed 相似,但如果 signed_id 已过期、目的不匹配、用于其他记录或被篡改,则会引发 ActiveSupport::MessageVerifier::InvalidSignature 异常。如果有效签名 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 72
def find_signed!(signed_id, purpose: nil)
  if id = signed_id_verifier.verify(signed_id, purpose: combine_signed_id_purposes(purpose))
    find(id)
  end
end

signed_id_verifier()

所有签名 ID 生成的验证器实例,并从该实例验证。默认情况下,它将使用类级 signed_id_verifier_secret 初始化,在 Rails 中,它来自 Rails.application.key_generator。默认情况下,它是 SHA256 用于摘要,JSON 用于序列化。

# File activerecord/lib/active_record/signed_id.rb, line 81
def signed_id_verifier
  @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"
    else
      ActiveSupport::MessageVerifier.new secret, digest: "SHA256", serializer: JSON, url_safe: true
    end
  end
end

signed_id_verifier=(verifier)

允许您传入一个自定义验证器,用于签名 ID。这也允许您对不同的类使用不同的验证器。如果您需要轮换密钥,这也很有用,因为您可以提前准备好您的自定义验证器。有关详细信息,请参阅 ActiveSupport::MessageVerifier

# File activerecord/lib/active_record/signed_id.rb, line 97
def signed_id_verifier=(verifier)
  @signed_id_verifier = verifier
end