3. 鉴权拦截核心概念:Token、Session、JWT、OAuth2.0 基础概念与 Redis 缓存的关系

在构建后端鉴权拦截系统时,Token、Session、JWT 和 OAuth2.0 是四个最核心的概念。它们各自解决了不同场景下的身份认证与授权问题,而 Redis 作为高性能缓存数据库,在其中扮演了关键的“状态存储”与“令牌管理”角色。理解它们之间的区别与联系,是设计可靠鉴权架构的前提。

3.1 核心概念速览

概念 本质 状态存储位置 是否自包含 Redis 典型作用
Session 服务端会话对象 服务端内存 / Redis 否(依赖服务端存储) 集中存储 Session 数据,实现分布式会话共享
Token 访问凭证字符串 客户端持有,服务端可验证 视实现方式而定 存储黑名单、刷新令牌、速率限制计数器
JWT 自包含的 Token 标准 客户端持有,服务端无状态验证 是(包含用户信息与签名) 存储 JWT 黑名单、刷新令牌、临时授权码
OAuth2.0 授权框架协议 授权服务器 + 资源服务器 否(依赖授权码、令牌端点) 存储授权码、访问令牌、刷新令牌、客户端信息
工程经验: 在微服务架构中,Session 模式因需要共享状态而逐渐被 JWT 替代,但 JWT 的“无状态”特性也带来了无法主动失效的问题。Redis 恰好弥补了这一缺陷——通过维护 JWT 黑名单,实现“有状态的无状态鉴权”。

3.2 Session 与 Redis:从单体到分布式

传统的 Session 鉴权流程:用户登录后,服务端创建 Session 对象,将 Session ID 写入 Cookie 返回给客户端。后续请求携带 Cookie,服务端根据 Session ID 查找内存中的 Session 数据。

单体架构下的问题: 当应用部署多台服务器时,用户的请求可能被负载均衡转发到不同节点,导致 Session 数据无法共享(Session 丢失)。

Redis 解决方案: 将 Session 数据从本地内存迁移到 Redis 集中存储。所有应用节点通过统一的 Redis 读取 Session,实现跨节点会话共享。

// Spring Session + Redis 配置示例
@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800)
public class RedisSessionConfig {
    @Bean
    public LettuceConnectionFactory redisConnectionFactory() {
        return new LettuceConnectionFactory("redis-master", 6379);
    }
}
关键指标: 使用 Redis 存储 Session 后,单次 Session 读取延迟通常 < 1ms(内网),支持 TTL 自动过期,无需手动清理过期会话。

3.3 JWT 与 Redis:无状态令牌的有状态补充

JWT(JSON Web Token)由 Header、Payload、Signature 三部分组成,服务端通过验证签名即可确认令牌合法性,无需查询数据库。但“无状态”也意味着:

  • 无法主动失效: 签发后直到过期前都有效,无法强制用户下线。
  • 无法检测令牌泄露: 被盗用的 JWT 在有效期内可被任意使用。
  • Payload 大小受限: 不宜存放过多用户信息,否则每次请求都携带大量数据。

Redis 的补充角色:

  1. JWT 黑名单(Blacklist): 用户登出或修改密码时,将当前 JWT 的 jti(JWT ID)存入 Redis,设置 TTL 为令牌剩余有效期。鉴权拦截时先检查 Redis 黑名单。
  2. 刷新令牌(Refresh Token)存储: 长期有效的 Refresh Token 存入 Redis,访问令牌过期后通过 Refresh Token 换取新令牌。
  3. 临时授权码(Authorization Code): OAuth2.0 授权码流程中,授权码存入 Redis,设置短 TTL(通常 5 分钟)。
// JWT 黑名单校验伪代码
public boolean isTokenBlacklisted(String jti) {
    // 使用 Redis 的 EXISTS 命令检查
    return redisTemplate.hasKey("jwt:blacklist:" + jti);
}

// 用户登出时加入黑名单
public void logout(String jti, long ttlSeconds) {
    redisTemplate.opsForValue().set(
        "jwt:blacklist:" + jti, 
        "1", 
        ttlSeconds, 
        TimeUnit.SECONDS
    );
}
避坑提示: JWT 黑名单的 TTL 必须与令牌剩余有效期一致,否则会出现“黑名单已过期但令牌仍有效”的安全漏洞。建议在签发 JWT 时记录过期时间戳,登出时计算剩余秒数。

3.4 OAuth2.0 与 Redis:授权码模式的缓存基石

OAuth2.0 定义了四种授权模式,其中授权码模式(Authorization Code Grant)是最常用、最安全的流程。Redis 在该模式中承担了多个关键数据的临时存储:

数据项 Redis Key 设计 TTL 说明
授权码 oauth:code:{code} 5 分钟 一次性使用,使用后立即删除
访问令牌 oauth:access:{token} 2 小时 资源服务器通过 Redis 验证令牌有效性
刷新令牌 oauth:refresh:{token} 30 天 用于续期访问令牌,支持轮换策略
客户端信息 oauth:client:{clientId} 长期(无过期) 缓存客户端密钥、回调地址、授权范围
工程实践: 在 Spring Security OAuth2 中,默认使用 InMemoryTokenStore 或 JdbcTokenStore。生产环境建议替换为 RedisTokenStore,利用 Redis 的原子性操作和 TTL 机制,避免数据库频繁读写。

3.5 鉴权拦截中的 Redis 数据流

下图展示了在 OAuth2.0 + JWT 混合架构中,Redis 如何贯穿整个鉴权拦截流程:

OAuth2.0 + JWT 鉴权拦截 Redis 数据流 客户端 授权服务器 资源服务器 Redis 缓存 授权码 / 令牌 / 黑名单 1. 请求授权码 2. 存储授权码 3. 换取访问令牌 4. 验证并删除 5. 携带 JWT 请求资源 6. 检查黑名单 7. 返回验证结果 8. 返回资源 / 拒绝 流程说明: 1. 客户端向授权服务器请求授权码,授权服务器生成授权码并存入 Redis(TTL=5min)。 2. 客户端使用授权码换取访问令牌(JWT),授权服务器验证授权码后删除,签发 JWT。 3. 客户端携带 JWT 访问资源服务器,资源服务器先验证 JWT 签名,再查询 Redis 黑名单。 4. 若 JWT 未在黑名单中且签名有效,则放行;否则返回 401 未授权。 5. 用户登出时,授权服务器将 JWT 的 jti 加入 Redis 黑名单,TTL 设为令牌剩余有效期。

3.6 四种鉴权模式的 Redis 选型建议

场景 推荐方案 Redis 数据结构 注意事项
传统单体应用 Session + Redis String(Session 序列化) 注意 Session 序列化性能,避免大对象
微服务内部鉴权 JWT + Redis 黑名单 Set / String(黑名单) 黑名单 TTL 必须精确计算,建议使用 Lua 脚本原子操作
第三方开放平台 OAuth2.0 + Redis TokenStore Hash / String(令牌+客户端信息) 授权码必须一次性使用,使用 Redis 的 DEL 原子性
移动端 / SPA JWT + Refresh Token String(Refresh Token)+ Set(黑名单) Refresh Token 支持轮换,旧令牌立即失效

3.7 常见故障与排查方向

  • Session 丢失: 检查 Redis 连接是否正常、Session Key 是否被误删除、TTL 是否过短。
  • JWT 黑名单失效: 确认黑名单 TTL 计算逻辑是否正确,Redis 时钟是否与服务器同步。
  • OAuth2.0 授权码重复使用: 检查授权码消费时是否使用 Redis 的原子删除操作(GET + DEL 或 Lua 脚本)。
  • Redis 内存暴涨: 检查令牌黑名单是否未设置 TTL,或 Refresh Token 未及时清理。
核心结论: 无论采用 Session、JWT 还是 OAuth2.0,Redis 都是鉴权拦截系统中不可或缺的“状态层”。它解决了分布式环境下的会话共享、令牌主动失效、临时凭证存储等核心问题。理解这四者的关系,是设计高可用鉴权架构的第一步。