共计 4360 个字符,预计需要花费 11 分钟才能阅读完成。
小小持续学习,这次学习的内容是 egg-jwt 相干。
创立 egg 我的项目
这里创立一个 egg 新我的项目,这里应用的是 ts 模式。
npm init egg --type=ts
npm install
装置相干的包
这里创立并装置实现当前,须要再次初始化俩包,别离为 egg-cors 与 egg-jwt token 生成的验证包
npm install egg-cors egg-jwt --save
配置相干插件
这里配置相干的插件
import {EggPlugin} from 'egg';
const plugin: EggPlugin = {
jwt: {
enable: true,
package: "egg-jwt"
},
cors: {
enable: true,
package: 'egg-cors',
}
};
export default plugin;
配置默认配置文件
config.jwt = {secret: "123456"// 自定义 token 的加密条件字符串};
config.security = {
csrf: {
enable: false,
ignoreJSON: true
},
domainWhiteList: ['http://localhost:8080'],// 容许拜访接口的白名单
};
config.cors = {
origin:'*',
allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH'
};
这里配置实现了相干的默认配置
在根目录申明 any 类型
这里须要在跟目录申明一个 any 类型,用于前后端发送相干的字符串参数。
import 'egg';
declare module 'egg' {
interface Application {jwt: any;}
}
配置相干路由
这里在 app/router.ts 创立相干的路由
import {Application} from 'egg';
export default (app: Application) => {const { controller, router, jwt} = app;
// 失常路由
router.post('/admin/login', controller.admin.login);
/*
* 这里的第二个对象不再是控制器,而是 jwt 验证对象,第三个中央才是控制器
* 只有在须要验证 token 的路由才须要第二个 是 jwt 否则第二个对象为控制器
**/
router.post('/admin',jwt, controller.admin.index);
};
这里就配置实现了相干的路由。
编写路由对应的控制器
这里编写路由所对应的控制器
这个控制器在 app/controller/home.ts 目录下
import {Controller} from 'egg';
export default class AdminController extends Controller {
// 验证登录并且生成 token
public async login() {const { ctx ,app} = this;
// 获取用户端传递过去的参数
const data = ctx.request.body;
// 进行验证 data 数据 登录是否胜利
// .........
// 胜利过后进行一下操作
// 生成 token 的形式
const token = app.jwt.sign({
username: data.username, // 须要存储的 token 数据
//......
}, app.config.jwt.secret);
// 生成的 token = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE1NjAzNDY5MDN9.B95GqH-fdRpyZIE5g_T0l8RgzNyWOyXepkLiynWqrJg
// 返回 token 到前端
ctx.body = token;
};
// 拜访 admin 数据时进行验证 token,并且解析 token 的数据
public async index() {const { ctx ,app} = this;
console.log(ctx.state.user);
/*
* 打印内容为:{username : 'admin', iat: 1560346903}
* iat 为过期工夫,能够独自写中间件验证,这里不做细究
* 除了 iat 之后,其余的为过后存储的数据
**/
ctx.body = {code:0,msg:'验证胜利'};
}
}
前端申请相匹配
这里只须要在前端的 authorization 字段里,增加相干的配置信息即可。
axios({
method: 'post',
url: 'http://127.0.0.1:7001/admin',
data: {
username: 'admin',
lastName: '123456'
},
headers:{
// 切记 token 不要间接发送,要在后面加上 Bearer 字符串和一个空格
'Authorization':`Bearer ${token}`
}
}).then(res=>{console.log(res.data)
})
这里就实现了 egg.js 联合 jwt 实现相干的验证
小 tips
这里插曲一个小 tips,这里应用的是 jsonwebtoken。这里应用 jsonwebtoken 实现 token 相干认证机制。
装置
这里装置相干的依赖
npm install jsonwebtoken
编写中间件
在 middleware 文件下新建一个 jwt.ts 文件
'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 生成
这里卸载文件里,用于调用,生成相干的 token
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
}
调用相干的生成办法
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,在前面加上相干的空格。
例: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)
})
这里就实现了相干 jwt 的生成与应用。
正文完