跳至内容 跳至搜索
方法
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 42
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 62
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 71
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
    end
  end
end

signed_id_verifier=(verifier)

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

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