通过这篇 全栈项目|小书架|服务器开发-JWT 详解 文章我们对
JWT
有了深入的了解,那么接下来介绍JWT
如何在项目中使用。
$ npm install jsonwebtoken
将生成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
是一个中间件框架,那么就可以通过中间件的方式去实现
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
不需要括号,因为是属性,不是方法
通过调用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
中携带的数据了。
在获取热搜书籍接口中取出先前传递的uid
和scope
:
router.get('/search/hot', new Auth().m,async ctx => {
ctx.body = {
'uid':ctx.auth.uid,
'scope': ctx.auth.scope
}
})