全栈项目|小书架|服务器开发-NodeJS 使用 JWT 实现登录认证

通过这篇 全栈项目|小书架|服务器开发-JWT 详解 文章我们对JWT有了深入的了解,那么接下来介绍JWT如何在项目中使用。

安装

$ npm install jsonwebtoken

生成 Token

将生成token的代码封装到一个函数中,方便后续调用。

/**
 * 生成 token
 * @param {用户 id} uid 
 * @param {*} scope 
 */
const generateToken = function (uid, scope) {
	// 配置项中的密钥和过期时间
    const secretKey = global.config.security.secretKey
    const expiresIn = global.config.security.expiresIn
    
    // 接收三个参数,第一个是载荷,用于编码后存储在 token 中的数据,也是验证 token 后可以拿到的数据;
    // 第二个是密钥,自己定义的,验证的时候也是要相同的密钥才能解码;
    // 第三个是options,可以设置 token 的过期时间。
    const token = jwt.sign({
        uid,
        scope
    }, secretKey, {
        expiresIn: expiresIn
    })
    return token
}

有些api用户是没权限访问,比如用户只有总管理员可以查看统计数据,而普通用户访问会提示权限不足,如何去实现这个功能呢?

koa是一个中间件框架,那么就可以通过中间件的方式去实现

拦截器中间件

  1. 定义一个中间件
  2. 在接口访问时调用中间件验证

Auth.js权限验证中间件

const basicAuth = require('basic-auth')
const jwt = require('jsonwebtoken')

class Auth {
    /**
     * @param {用户权限等级} level 
     */
    constructor(level) {
        this.level = level || 1
        Auth.USER = 8
        Auth.ADMIN = 16
        Auth.SUPER_ADMIN = 32
    }

    get m() {
        return async (ctx, next) => {
            
            const userToken = basicAuth(ctx.req)
            let errMsg = 'token不合法'

            if (!userToken || !userToken.name) {
                throw new global.errs.Forbidden(errMsg)
            }
            // 校验 token 令牌
            try {
                var decode = jwt.verify(userToken.name, 
                    global.config.security.secretKey)
            } catch (error) {
                if (error.name == 'TokenExpiredError'){
                    errMsg = 'token已过期'
                }
                // token不合法
                throw new global.errs.Forbidden(errMsg)
            }

            if(decode.scope < this.level){
                errMsg = '权限不足'
                throw new global.errs.Forbidden(errMsg)
            }

            // uid,scope
            ctx.auth = {
                uid:decode.uid,
                scope:decode.scope
            }

            await next()
        }
    }

}

module.exports = {
    Auth
}

调用中间件验证权限

router.get('/search/hot',  new Auth().m,async ctx => {
	ctx.body = {
		'uid':ctx.auth.uid,
		'scope': ctx.auth.scope
	}
})

ps: new Auth().m 中的m不需要括号,因为是属性,不是方法

验证 Token

通过调用jwt.verify,判断是否出错,没有出错则token有效,否则token无效。

在验证token时就可以获取到携带的数据,有两种方式:
(1)通过jwt.verify直接返回
(2)通过jwt.verify保存在ctx.auth然后需要的时候再返回。

方式1:

static verifyToken(token){
        try{
            let userData = {}
            jwt.verify(token, global.config.security.secretKey, (err, data) => {
                if(err) {
                    throw new global.errs.HttpException("验证失败",-1)
                } else {
                	// data 中就包含 jwt.verify 验证通过之后的数据
                    userData =  data
                }
            })
            return userData
        }
        catch (error){
            throw new global.errs.HttpException("验证失败",-1)
        }

    }

方式2:
通过权限验证之后,就可以在接口请求中获取到数据 jwt中携带的数据了。

在获取热搜书籍接口中取出先前传递的uidscope

router.get('/search/hot',  new Auth().m,async ctx => {
	ctx.body = {
		'uid':ctx.auth.uid,
		'scope': ctx.auth.scope
	}
})

参考


在这里插入图片描述

发布了180 篇原创文章 · 获赞 76 · 访问量 14万+

猜你喜欢

转载自blog.csdn.net/ITxiaodong/article/details/103114927