一, 前言
JWT(JSON web Token), 是为了在网络环境间传递声明而执行的一种基于 JSON 的开放标准 (RFC 7519).
JWT 不是一个新鲜的东西, 网上相关的介绍已经非常多了. 不是很了解的可以在网上搜索一下相关信息.
同步 sau 交流学习社区: https://www.mwcxs.top/page/454.html https://www.mwcxs.top/page/454.html
二, 源码
Talk is cheap. Show me the code. https://github.com/saucxs/songEagle_backManage
三, 工作流程
JWT 本质来说是一个 token. 在前后端进行 HTTP 连接时来进行相应的验证.
1. 博客的后台管理系统发起登录请求, 后端服务器校验成功之后, 生成 JWT 认证信息;
2. 前端接收到 JWT 后进行存储;
3. 前端在之后每次接口调用发起 HTTP 请求时, 会将 JWT 放到 HTTP 的 headers 参数里的 authorization 中一起发送给后端;
4. 后端接收到请求时会根据 JWT 中的信息来校验当前发起 HTTP 请求的用户是否是具有访问权限的, 有访问权限时则交给服务器继续处理, 没有时则直接返回 401 错误.
四, 实现过程
1. 登录成功生成 JWT
说明: 以下代码只保留了核心代码, 详细代码可在对应文件中查看, 下同.
- // /server/API/admin/admin.controller.JS
- const jwt = require('jsonwebtoken');
- const config = require('../../config/config');
- exports.login = async(ctx) => {
- // ...
- if (hashedPassword === hashPassword) {
- // ...
- // 用户 token
- const userToken = {
- name: userName,
- id: results[0].id
- };
- // 签发 token
- const token = jwt.sign(userToken, config.tokenSecret, { expiresIn: '2h' });
- // ...
- }
- // ...
- }
2. 添加中间件校验 JWT,
- // /server/middlreware/tokenError.JS
- const jwt = require('jsonwebtoken');
- const config = require('../config/config');
- const util = require('util');
- const verify = util.promisify(jwt.verify);
- /**
- * 判断 token 是否可用
- */
- module.exports = function () {
- return async function (ctx, next) {
- try {
- // 获取 jwt
- const token = ctx.header.authorization;
- if (token) {
- try {
- // 解密 payload, 获取用户名和 ID
- let payload = await verify(token.split(' ')[1], config.tokenSecret);
- ctx.user = {
- name: payload.name,
- id: payload.id
- };
- } catch (err) {
- console.log('token verify fail:', err)
- }
- }
- await next();
- } catch (err) {
- if (err.status === 401) {
- ctx.status = 401;
- ctx.body = {
- success: 0,
- message: '认证失败'
- };
- } else {
- err.status = 404;
- ctx.body = {
- success: 0,
- message: '404'
- };
- }
- }
- }
- }
3. Koa.JS 中添加 JWT 处理
此处在开发时需要过滤掉登录接口 (login), 否则会导致 JWT 验证永远失败.
- // /server/config/koa.JS
- const jwt = require('koa-jwt');
- const tokenError = require('../middlreware/tokenError');
- // ...
- const App = new Koa();
- App.use(tokenError());
- App.use(bodyParser());
- App.use(koaJson());
- App.use(resource(path.join(config.root, config.appPath)));
- App.use(jwt({
- secret: config.tokenSecret
- }).unless({
- path: [/^\/backapi\/admin\/login/, /^\/blogapi\//]
- }));
- module.exports = App;
4. 前端处理
前端开发使用的是 vue.js, 发送 HTTP 请求使用的是 axios.
1. 登录成功之后将 JWT 存储到 localStorage 中 (可根据个人需要存储, 我个人是比较喜欢存储到 localStorage 中).
- methods: {
- login: async function () {
- // ...
- let res = await API.login(this.userName, this.password);
- if (res.success === 1) {
- this.errMsg = '';
- localStorage.setItem('SONG_EAGLE_TOKEN', res.token);
- this.$router.push({ path: '/postlist' });
- } else {
- this.errMsg = res.message;
- }
- }
- }
2. vue.JS 的 router(路由) 跳转前校验 JWT 是否存在, 不存在则跳转到登录页面.
- // /src/router/index.JS
- router.beforeEach((to, from, next) => {
- if (to.meta.requireAuth) {
- const token = localStorage.getItem('SONG_EAGLE_TOKEN');
- if (token && token !== 'null') {
- next();
- } else {
- next('/login');
- }
- } else {
- next();
- }
- });
3. axios 拦截器中给 HTTP 统一添加 Authorization 信息
- // /src/API/config.JS
- axios.interceptors.request.use(
- config => {
- const token = localStorage.getItem('SONG_EAGLE_TOKEN');
- if (token) {
- // Bearer 是 JWT 的认证头部信息
- config.headers.common['Authorization'] = 'Bearer' + token;
- }
- return config;
- },
- error => {
- return Promise.reject(error);
- }
- );
4. axios 拦截器在接收到 HTTP 返回时统一处理返回状态
- // /src/main.JS
- axios.interceptors.response.use(
- response => {
- return response;
- },
- error => {
- if (error.response.status === 401) {
- Vue.prototype.$msgBox.showMsgBox({
- title: '错误提示',
- content: '您的登录信息已失效, 请重新登录',
- isShowCancelBtn: false
- }).then((val) => {
- router.push('/login');
- }).catch(() => {
- console.log('cancel');
- });
- } else {
- Vue.prototype.$message.showMessage({
- type: 'error',
- content: '系统出现错误'
- });
- }
- return Promise.reject(error);
- }
- );
五, 总结
这个基本上就是 JWT 的流程. 当然单纯的 JWT 并不是说绝对安全的, 不过对于一个个人博客系统的认证来说还是足够的.
来源: https://www.cnblogs.com/chengxs/p/10010303.html