您的位置:首页 > Web前端 > JavaScript

egg基于jsonwebtoken的Token实现认证机制

2019-04-29 11:54 363 查看

Json web token(JWT)是为了网络应用环境间传递声明而执行的一种基于JSON的开发标准(RFC 7519),该token被设计为紧凑且安全的,特别适用于分布式站点的单点登陆(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

相关技术点

eggmiddleware

jwt官网

node-jsonwebtoken

安装

npm install jsonwebtoken

Middleware中间件编写

在middleware文件下新建一个jwt.js文件

'use strict'
const fs = require('fs')
const path = require('path')
const jwt = require('jsonwebtoken') //引入jsonwebtoken

module.exports = (options, app) => {
return async function userInterceptor(ctx, next) {
let authToken = ctx.header.authorization // 获取header里的authorization
if (authToken) {
authToken = authToken.substring(7)
const res = verifyToken(authToken) // 解密获取的Token
if (res.corpid && res.userid) {
// 如果需要限制单端登陆或者使用过程中废止某个token,或者更改token的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效
// 此处使用redis进行保存
const redis_token = await app.redis.get('loginToken').get(res.corpid + res.userid) // 获取保存的token
if (authToken === redis_token) {
ctx.locals.corpid = res.corpid
ctx.locals.userid = res.userid
await next()
} else {
ctx.body = { code: 50012, msg: '您的账号已在其他地方登录' }
}
} else {
ctx.body = { code: 50012, msg: '登录状态已过期' }
}
} else {
ctx.body = { code: 50008, msg: '请登陆后再进行操作' }
}
}
}

// 解密,验证
function verifyToken(token) {
const cert = fs.readFileSync(path.join(__dirname, '../public/rsa_public_key.pem')) // 公钥,看后面生成方法
let res = ''
try {
const result = jwt.verify(token, cert, { algorithms: [ 'RS256' ] }) || {}
const { exp } = result,
current = Math.floor(Date.now() / 1000)
if (current <= exp) res = result.data || {}
} catch (e) {
console.log(e)
}
return res
}

使用中间件

在 config.default.js 中加入下面的配置就完成了中间件的开启和配置

// 方法一:在应用中使用中间件
config.middleware = [ 'jwt' ]

config.jwt = {
enable: true,
ignore: [ '/api/v1/test/', '/public/' ], // 哪些请求不需要认证
}

// 方法二:router中使用中间件
module.exports = app => {
const jwt = app.middleware.jwt();
app.router.get('/api/v1/test/', jwt, app.controller.test.test);
};

token生成

建议写在helper里,方便调用

loginToken(data, expires = 7200) {
const exp = Math.floor(Date.now() / 1000) + expires
const cert = fs.readFileSync(path.join(__dirname, '../public/rsa_private_key.pem')) // 私钥,看后面生成方法
const token = jwt.sign({ data, exp }, cert, { algorithm: 'RS256' })
return token
}

调用token生成方法

const token = ctx.helper.loginToken({ corpid: usersData.corpid, userid: usersData.userid }, 7200) // token生成
await app.redis.get('loginToken').set(usersData.corpid + usersData.userid, token, 'ex', 7200) // 保存到redis
ctx.body = { data: { token, expires: this.config.login_token_time }, code: 1, msg: '登录成功' } // 返回前端

前端使用

设置headers的

Authorization = 'Bearer ' + Token

Bearer后面要加空格

例:axios中
// request拦截器
service.interceptors.request.use(config => {
if (store.getters.token) {
config.headers['Authorization'] = `Bearer ${getToken()}`
}
return config
}, error => {
console.log(error)
Promise.reject(error)
})

利用Openssl生成私钥公钥

此处介绍window下已安装git的方法
设置环境变量
我的电脑 > 右键 > 属性 > 高级系统设置 > 环境变量 > path > 编辑 > 新建

git路径\bin
git路径\usr\bin

如:
C:\Program Files\Git\bin
C:\Program Files\Git\usr\bin

生成公钥:
openssl genrsa -out rsa_private_key.pem 1024

生成私钥:
openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: