一、koa token生成、验证
koa-jwt官网
https://github.com/koajs/jwt
推荐一个koa-jwt学习文档:
https://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html
jsonwebtoken方法添加
const { sign, verify } = require('jsonwebtoken');
const secretKey = "cariadakkodis";module.exports = {// 获取tokengetToken(ctx) {return ctx.request.headers.Authorization || '';},// 加密signToken(userInfo){// 定义 secret 密钥const token = sign({ username: userInfo.username, password: userInfo.password },secretKey,{ expiresIn: '1h' }// { expiresIn: 10 } // 10s);return token;},// 验签verifyToken(token){return verify(token, secretKey);},// 将secretKey返回secretKey
}
app.js 中添加
const jwt = require("koa-jwt");
const token = require("./utils/token.js");// 对没有验签通过返回的错误进行拦截处理
app.use(async (ctx, next) => {// 如果token没有经过验证中间件会返回401错误,可以通过下面的中间件自定义处理这个错误await next().catch((err)=>{if (401 === err.status) {ctx.status = 401;ctx.body = {data: '没有找到token信息,请检查接口请求头信息'};console.log("未找到token: "+ err);} else {console.log(err);throw err;}});
});// unless 某些特殊接口不验证toekn 比如登录
app.use(jwt({ secret: token.secretKey }).unless({ path: [/^\/api\/user\/login/]}));// 这下面添加route逻辑
app.use(index.routes(), index.allowedMethods());
这样就可以了 我们用 jsonwebtoken生成token,koa-jwt来验证token,
上面是 koa-jwt 源码中的一个文件,获取到 token,这里就明确了一个点,前端接口在header中需要使用 authorization 字段传递 token
二、具体业务处理
我们再看下 login登录的接口怎么处理,下面涉及到具体业务代码看不懂也没关系,上面的代码已经实现了 koa token的使用、验证。
我用的是 elasticSearch 数据库
这里routes文件是对接的接口
controller文件 控制层 具体的接口逻辑
modules文件 连接数据库的操作
const router = require('koa-router')();
// 导入 controller
const user = require('../controller/User.js');
router.prefix('/api/user');
router.post('/login', user.loginFun);
module.exports = router;
const Base = require('../modules/base.js');
const modulesBase = new Base();
const token = require('../utils/token.js');
class User {constructor() {}async loginFun(ctx, next) {const registerBody = ctx.request.body;console.log(registerBody);let result = await modulesBase.searchUser({query: {bool: {must: [{match: {username: registerBody.username}},{match: {password: registerBody.password}}]}}});if (result.hits && result.hits.hits.length) {ctx.body = {data: {data: {role: result.hits.hits[0]._source.role,username: result.hits.hits[0]._source.username},message: 'success',success: true,token: token.signToken({username: registerBody.username, password: registerBody.password})}};return;}ctx.body = {data: {data: null,message: 'Incorrect account or password',success: false}};}
}
module.exports = new User();
const Db = require('../db/index');
class BaseModule {constructor() {const db = new Db();this.environment = db.getEnvironment()['environment'];this.elasticSearch = db.elasticSearch();}async search(params) {return await this.elasticSearch.search(Object.assign({index: 'data-viz-test'}, params));}async update(params) {return await this.elasticSearch.update(Object.assign({index: 'data-viz-test'}, params));}async searchUser(params) {return await this.elasticSearch.search(Object.assign({index: 'users'}, params));}
}module.exports = BaseModule;
三、下面我们来看下前端代码
request({url: '/user/login',method: 'post',data: {username: ruleForm.username,password: ruleForm.password}}).then((res) => {if (res.data.success && res.data && res.data.data) {const role = res.data.data.role;const username = res.data.data.username;const token = res.data.token;localStorage.setItem('role', role);localStorage.setItem('username', username);localStorage.setItem('token', token);router.push('/');return;}ElMessage({type: 'warning',message: res.data.message});});
request.ts
// service.ts
import axios from 'axios';
import { ElMessage } from 'element-plus';
const service = axios.create({baseURL: '/api',timeout: 1000 * 30, // 超时时间headers: {'Content-Type': 'application/json;charset=utf-8'},validateStatus () {return true;}
});service.interceptors.request.use((config: any) => {// 添加请求头以及其他逻辑处理const token = localStorage.getItem('token');if (token) {// Bearer 后面加空格 这也是 koa-jwt 的要求config.headers['Authorization'] = `Bearer ${token}`;}return config;},(error: any) => {Promise.resolve(error);}
);/*** 响应拦截器*/
service.interceptors.response.use((response: any) => {// console.log('响应拦截:拦截事件可以放这里', response)// 后端status错误判断if (response.status === 200) {return Promise.resolve(response.data);}if (response.status === 401) {ElMessage({message: 'Authentication expired',type: 'warning',});localStorage.removeItem('token');localStorage.removeItem('username');localStorage.removeItem('role');window.location.href = '/login';return response.data;}return Promise.reject(response.data);},(error: any) => {// Http错误状态码处理console.log('error----');console.log(error);return Promise.reject(error);}
);
export default service;