Help us learn about your current experience with the documentation. Take the survey.

使用 TokenAuthenticatable concern

TokenAuthenticatable 模块是一个 concern,为 ActiveRecord 模型提供基于令牌的认证功能。 它允许你为模型定义认证令牌。

概述

该模块提供了一种灵活的方式,为你的模型添加基于令牌的认证。

它支持三种存储策略:

  • digest:在数据库中存储令牌的 SHA256 摘要
  • encrypted:使用 AES 256 GCM 算法在数据库中存储加密的令牌
  • insecure:令牌以原样存储(不加密也不摘要)在数据库中。我们强烈不建议使用此策略。

它还支持每种存储策略的多个选项。

使用方法

要在模型中定义 token_field 属性,请包含该模块并调用 add_authentication_token_field

class User < ApplicationRecord
  include TokenAuthenticatable

  add_authentication_token_field :token_field, encrypted: :required
end

存储策略

  • encrypted: :required:将加密的令牌存储在 token_field_encrypted 列中。 token_field_encrypted 列必须存在。我们强烈建议使用此策略。
  • encrypted: :migrating:在 token_field_encryptedtoken_field 中存储加密和明文令牌。 始终读取明文令牌。这应在属性正在过渡到加密时使用。 token_fieldtoken_field_encrypted 列都必须存在。
  • encrypted: :optional:将加密的令牌存储在 token_field_encrypted 列中。 优先从 token_field_encrypted 读取,如果不存在则回退到 token_field。 在写入加密令牌时,将 token_field 列中的明文令牌设为 null。 token_fieldtoken_field_encrypted 列都必须存在。
  • digest: true:在数据库中存储令牌的摘要。 token_field_digest 列必须存在。
  • insecure: true:将令牌以原样(不加密也不摘要)存储在数据库中。我们强烈不建议使用此策略。

如果没有选择存储策略,默认会在数据库中存储令牌的 SHA256 摘要。

token_field_encrypted 列应该始终被索引,因为它用于执行令牌的唯一性检查和查找。

其他选项

  • unique: false:不强制令牌唯一性,并禁用 find_by_token_field 的生成(其中 token_field 是属性名)。默认为 true
  • format_with_prefix: :compute_token_prefix:允许为令牌定义前缀。#compute_token_prefix 方法需要返回一个 String。默认无前缀。
  • expires_at: :compute_token_expiration_time:允许定义令牌应该过期的时间。 #compute_token_expiration_time 方法需要返回一个 Time 对象。默认不过期。
  • token_generator::一个返回令牌的 proc。如果不存在,则使用 Devise.friendly_token 生成随机令牌。
  • routable_token::一个哈希,允许定义应该在令牌中编码的"可路由"部分。 这遵循 Routable Tokens 设计文档。 支持的键有:
    • if::一个接收令牌所有者记录的 proc。该 proc 通常包含功能标志检查和/或其他检查。 如果 proc 返回 false,则使用 Devise.friendly_token 生成随机令牌。
    • payload::一个 { key => proc } 哈希,允许的键为 c, o, g, p, u,这些键 符合规范。 示例见 Routable Tokens 设计文档
  • require_prefix_for_validation:(仅适用于 :encrypted 策略):检查令牌前缀是否匹配预期前缀。如果前缀不匹配,其行为就像令牌未设置一样。默认为 false

访问和操作令牌

user = User.new
user.token_field # 获取令牌
user.set_token_field('new_token') # 设置新令牌
user.ensure_token_field # 如果不存在则生成令牌
user.ensure_token_field! # 如果不存在则生成令牌
user.reset_token_field! # 重置令牌并使用 #save! 保存模型
user.token_field_matches?(other_token) # 安全地将令牌与另一个令牌比较
user.token_field_expires_at # 返回过期时间
user.token_field_expired? # 检查令牌是否已过期
user.token_field_with_expiration # 返回一个 API::Support::TokenWithExpiration 对象,对 API 响应有用