node+koa+jsonwebtoken鉴权jwt实战

涉及到的库: 

 

如果对jwt不熟悉的话可以去了解一下前置知识:node实现jwt

主要是依靠jsonwebtoken的两个api:

生成token: sign()

校验token: verify()

这是我封装后的jwtUtils:

import jwt from 'jsonwebtoken';
import { sha256 } from "./cryptoUtils";
import { Context } from "koa";
import logger from './logger';
import emitter from './emitter';
import { HttpStatus } from '../middlewares/responseHandler';
export interface JwtOptions {
    secret: string;
    expiresIn: number;
    excludePath: Array<RegExp>;
}
export enum TokenErrorType {
    TOKEN_EXPIRED_ERROR = 'TokenExpiredError',
    JSON_WEB_TOKEN_ERROR = 'JsonWebTokenError'
}
class JwtUtils {
    public secret: string;
    public expiresIn: number;
    public excludePath: Array<RegExp>;
    private static instance: JwtUtils = null;
    public constructor(options: JwtOptions) {
        const { secret, expiresIn, excludePath } = options;
        logger.info(options)
        this.secret = sha256(secret);
        this.excludePath = excludePath
        this.expiresIn = expiresIn;
    }
    public async validateToken(ctx: Context, next): Promise<void> {
        const path = ctx.request.path;
        // 校验是否为请求白名单
        const isExcludePath = this.excludePath.some(function (e: RegExp) {
            return e.test(path);
        })
        if (isExcludePath) {
            return await next();
        }
        const token = (ctx.get('Authorization') || '').split(' ').pop();
        if (!token) {
            emitter.emit('errorResponse', ctx, HttpStatus.UNAUTHORIZED, '请求未携带token,请检查请求头');
            return;
        }
        try {
            const { id } = jwt.verify(token, this.secret) as { id: number } // 校验不通过会抛出错误
        } catch (error) {
            const { name } = error;
            switch (name) {
                case TokenErrorType.TOKEN_EXPIRED_ERROR: {
                    emitter.emit('errorResponse', ctx, HttpStatus.UNAUTHORIZED, 'token已过期');
                    break;
                }
                case TokenErrorType.JSON_WEB_TOKEN_ERROR: {
                    emitter.emit('errorResponse', ctx, HttpStatus.UNAUTHORIZED, '非法token');
                    break;
                }
                default:
                    break;
            }
            return;
        }
        await next()
    }
    public auth(ctx: Context, payload) {
        const token = jwt.sign(payload, this.secret, { expiresIn: this.expiresIn })
        return token;
    }
    public static getInstance() {
        if (!JwtUtils.instance) {
            JwtUtils.instance = new JwtUtils({
                excludePath: [
                    /\/user\/login/,
                    /\/swagger-html/,
                    /\/swagger-json/,
                    /\/uploads\/\w+/,
                    /\/captcha/,
                ],
                secret: 'Suk5201314lover',
                expiresIn: 60 * 60 * 24
            });
        }
        return JwtUtils.instance;
    }
}
const jwtUtils = Object.freeze(JwtUtils.getInstance());
export default jwtUtils;

首先生成token的api我们在用户授权也就是登录接口那里如果登录成功就要生成token和用户信息一起返回:

核心API说明:

sign方法传入的第一个参数就是用户载荷,也就是要加密的用户信息,可以传入用户id或者其他,第二个koa的上下文对象,第二个参数就是token加密的秘钥,这里博主用的sha256加密的秘钥,第三个options选项可以传入token过期时间,单位是秒

verify方法传入的第一个参数就是token,token来自用户请求的请求头信息,Bearer [token],把token截取出来就行了,第二个参数就是加密时的秘钥,这里传入用于解密token,返回值是sign方法传入的用户信息载荷,方法执行校验token如果失败就会抛出错误,就是利用这点来判断token是否有效

因为是通过koa中间件实现的,所以这里传入校验方法时是做为回调给koa去调用的,封装的this指向会错,所以手动指回来,这里是个细节划重点容易错

然后要注意的就是白名单要放行,不能拦截授权的接口,比如login,反正不用授权的都可以加入白名单

基本原理就是这样了,up主因为时间关系(懒)代码只贴了核心部分,主要是实现原理讲解,有不懂的地方可以留言或者私信up

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值