一、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;