FeathersJS 中实现 JWT 令牌吊销机制详解

FeathersJS 中实现 JWT 令牌吊销机制详解

feathers The API and real-time application framework feathers 项目地址: https://gitcode.com/gh_mirrors/fe/feathers

前言

在基于 JWT (JSON Web Token) 的身份验证系统中,令牌一旦签发就会在有效期内保持可用状态。本文将深入探讨如何在 FeathersJS 框架中实现 JWT 令牌的吊销机制,确保即使令牌未过期也能使其失效。

JWT 吊销的必要性

传统 Web 应用中,服务器可以通过销毁会话 ID 来注销用户。但在 JWT 的无状态认证中,由于服务器不存储令牌状态,要实现类似功能就需要额外机制。常见场景包括:

  1. 用户主动登出时使当前令牌失效
  2. 检测到可疑活动时强制终止会话
  3. 密码修改后使之前颁发的令牌失效

基础实现方案

核心思路

FeathersJS 的认证服务可通过扩展 AuthenticationService 类来实现令牌吊销功能。基本原理是:

  1. 维护一个已吊销令牌的存储
  2. 在验证令牌时检查是否已被吊销
  3. 登出时将令牌加入吊销列表

代码实现

const { AuthenticationService } = require('@feathersjs/authentication');
const { NotAuthenticated } = require('@feathersjs/errors');

// 存储已吊销的令牌
const revokedTokens = {};

class RevokableAuthService extends AuthenticationService {
  async revokeAccessToken(accessToken) {
    // 首先验证令牌是否有效
    const verified = await this.verifyAccessToken(accessToken);
    
    // 将令牌标记为已吊销
    revokedTokens[accessToken] = true;

    return verified;
  }

  async verifyAccessToken(accessToken) {
    // 检查令牌是否已被吊销
    if (revokedTokens[accessToken]) {
      throw new NotAuthenticated('令牌已被吊销');
    }

    return super.verifyAccessToken(accessToken);
  }

  async remove(id, params) {
    const authResult = await super.remove(id, params);
    const { accessToken } = authResult;

    if (accessToken) {
      // 登出时吊销当前令牌
      await this.revokeAccessToken(accessToken);
    }

    return authResult;
  }
}

// 使用自定义认证服务
app.use('/authentication', new RevokableAuthService(app));

方案优缺点

优点

  • 实现简单,无需额外依赖
  • 适合小型应用或开发环境

缺点

  • 内存存储,服务重启后吊销列表丢失
  • 不适合分布式环境
  • 长期运行可能导致内存增长

生产环境推荐方案:Redis 实现

对于生产环境,推荐使用 Redis 作为吊销令牌的存储后端,原因包括:

  1. 高性能的键值存储
  2. 支持自动过期(与 JWT 有效期天然契合)
  3. 适合分布式部署

Redis 实现代码

const redis = require('redis');
const { AuthenticationService } = require('@feathersjs/authentication');
const { NotAuthenticated } = require('@feathersjs/errors');

class RedisAuthService extends AuthenticationService {
  constructor(app, configKey) {
    super(app, configKey);
    
    // 初始化 Redis 客户端
    const client = redis.createClient();
    
    this.redis = {
      client,
      get: client.get.bind(client),
      set: client.set.bind(client),
      exists: client.exists.bind(client),
      expireat: client.expireat.bind(client)
    };

    // 连接 Redis
    (async () => {
      await this.redis.client.connect();
    })();
  }

  async revokeAccessToken(accessToken) {
    const verified = await this.verifyAccessToken(accessToken);
    // 计算剩余有效时间(秒)
    const expiry = verified.exp - Math.floor(Date.now() / 1000);

    // 存储到 Redis 并设置自动过期
    await this.redis.set(accessToken, '1', { EX: expiry });

    return verified;
  }

  async verifyAccessToken(accessToken) {
    if (await this.redis.exists(accessToken)) {
      throw new NotAuthenticated('令牌已被吊销');
    }

    return super.verifyAccessToken(accessToken);
  }

  // 登出逻辑保持不变
  async remove(id, params) {
    const authResult = await super.remove(id, params);
    const { accessToken } = authResult;

    if (accessToken) {
      await this.revokeAccessToken(accessToken);
    }

    return authResult;
  }
}

app.use('/authentication', new RedisAuthService(app));

Redis 方案优势

  1. 自动清理:Redis 的过期机制会自动清理已过期的吊销记录
  2. 分布式友好:多个服务实例可以共享同一个 Redis 存储
  3. 高性能:Redis 的读取速度极快,对认证流程影响小
  4. 持久化:即使服务重启,吊销记录也不会丢失

实现细节解析

令牌验证流程

  1. 客户端携带 JWT 访问受保护资源
  2. 服务端首先检查 Redis 中是否存在该令牌
  3. 如果存在则拒绝访问(令牌已被吊销)
  4. 不存在则继续正常验证流程

吊销流程

  1. 用户登出或管理员主动吊销令牌
  2. 服务端验证令牌有效性
  3. 计算令牌剩余有效时间
  4. 将令牌存入 Redis 并设置相同过期时间

过期处理

利用 Redis 的自动过期特性,当 JWT 自然过期后,对应的吊销记录也会自动清除,避免存储无限增长。

最佳实践建议

  1. 监控 Redis 内存使用:确保有足够内存存储所有活跃令牌的吊销记录
  2. 设置适当的内存淘汰策略:如 volatile-lru
  3. 考虑集群部署:高并发场景下使用 Redis 集群提高可用性
  4. 记录吊销日志:便于审计和安全分析
  5. 实现批量吊销:支持按用户ID吊销所有相关令牌

扩展思考

  1. 黑名单与白名单:本方案实现的是黑名单模式,也可考虑实现白名单模式(只允许特定的未吊销令牌)
  2. 多因素认证集成:结合吊销机制实现更灵活的安全策略
  3. 令牌刷新机制:与刷新令牌流程协同工作

总结

在 FeathersJS 中实现 JWT 吊销机制是增强应用安全性的重要手段。对于生产环境,Redis 方案提供了高性能、可扩展的解决方案。开发者应根据实际业务需求选择合适的实现方式,并注意相关的最佳实践。

feathers The API and real-time application framework feathers 项目地址: https://gitcode.com/gh_mirrors/fe/feathers

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

姬鸿桢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值