koa结合redis生成token

前言

之前我是将token挂载到上下文,这里做了笔记
但是后来我发现如果服务重启,他就失效。
业界常用的做法是将token放入redis管理

生成令牌

如果有 token 效期受 redis 控制了,那还要jwt就不要再控制了

import jwt from 'jsonwebtoken';
import { redis } from '../middleware/redis';

// 生成唯一令牌
const genToken = async (payload) => {
  const token = jwt.sign(payload, process.env.JWT_SECRET);
  // 只在Redis中控制过期时间
  await redis.set(`token:${token}`, JSON.stringify(payload), 'EX', 60 * 60);
  return token;
};

export default genToken;

移除原先的校验

并且移除 app.ts 中 koa-jwt 的校验代码,即下面代码就要删除了

// 1. 使用 koa-jwt 中间件(验证 JWT)
const koaJwt = KoaJwt({
  secret: process.env.JWT_SECRET,
}).unless({
  path: [
    /^\/api\/login$/,
    /^(?!\/api).*/,
    /^\/api\/send-code$/,
  ],
  custom: (ctx) => {
    // 放行带有 share 参数的 GET 请求
    if (ctx.method === 'GET' && ctx.query.share==='true') {
      return true;
    }
    return false;
  }
});
app.use(koaJwt);

加入新的校验

import jwt from 'jsonwebtoken';
import { redis } from './redis';
import context from '../utils/reques-context';

const redisJwt = async (ctx, next) => {
  // 跳过不需要验证的路径
  const skipPaths = [/^\/api\/login$/, /^(?!\/api).*/, /^\/api\/send-code$/];
  const shouldSkip = skipPaths.some((pattern) => pattern.test(ctx.path)) || (ctx.method === 'GET' && ctx.query.share === 'true');

  if (!shouldSkip && ctx.header?.authorization) {
    const token = ctx.header.authorization.replace('Bearer ', '');
    try {
      // 校验jwt token签名
      const info = jwt.verify(token, process.env.JWT_SECRET);

      console.log(info)

      // 检查Redis中是否存在该token
      const tokenData = await redis.get(`token:${token}`);
      if (!tokenData) {
        ctx.status = 401;
        ctx.body = { msg: 'Token已失效' };
        return;
      }

      ctx.state.userId = info.id;
      context.set('userId', ctx.state.userId);
    } catch (err) {
      ctx.status = 401;
      ctx.body = { msg: 'Token无效' };
      return;
    }
  } else if (!shouldSkip) {
    ctx.status = 401;
    ctx.body = { msg: '缺少认证信息' };
    return;
  }

  await next();
};
export default redisJwt;

使用

在入口中注册

// 1. 使用 redis-jwt 中间件(验证 JWT)
app.use(redisJwt);

在业务代码中使用

// 获取当前用户信息
router.get('/current', async (ctx) => {
  console.log(ctx.state.userId);
  const user = await queryOne({id:ctx.state.userId})
  ctx.body = JsonResult.success(user);
});
posted @ 2025-07-16 16:26  丁少华  阅读(9)  评论(0)    收藏  举报