一、koa token生成、验证
koa-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 = {
// 获取token
getToken(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;