sau交流学习社区--songEagle开发系列:Vue.js + Koa.js项目中使用JWT认证

一、前言

JWT(JSON Web Token),是为了在网络环境间传递声明而执行的一种基于JSON的开放标准(RFC 7519)。

JWT不是一个新鲜的东西,网上相关的介绍已经非常多了。不是很了解的可以在网上搜索一下相关信息。

同步sau交流学习社区:https://www.mwcxs.top/page/454.html

二、源码

Talk is cheap. Show me the code.

三、工作流程

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://github.com/saucxs/songEagle)

【后端】(https://github.com/saucxs/songEagle_backManage)

都已在GitHub上开源,目前在逐步完善功能中。欢迎感兴趣的同学fork和star。

原文地址:https://www.cnblogs.com/chengxs/p/10010303.html

时间: 2024-08-23 13:15:25

sau交流学习社区--songEagle开发系列:Vue.js + Koa.js项目中使用JWT认证的相关文章

sau交流学习社区—vue总结:使用vue的computed属性实现监控变量变化,使用vue的watch属性监控变量变化从而实现其他业务

有时候遇到这么个需求,输入框为空的时候,请求一遍接口,如果输入框不为空的时候,需要点击搜索按钮请求接口. 一.使用computed属性的实时监控计算 我第一反应是做一个computed属性监控这个输入框的值,一旦监控发现值为空,我就重新执行一遍请求的方法. <el-col :xs="8" :sm="8" :md="4" :lg="4" :xl="4"> <el-input v-model=

sau交流学习社区--看小说的lovebook一个无线端BS应用

一.前言 loveBook爱上阅读,是一款webapp的读小说等书籍的并且阅读的应用.如果觉得可以,欢迎fork和star. 自己最近在追斗破苍穹电视剧,下班时候在地铁上总听到有人说,斗破苍穹书籍比电视剧好看,于是想弄个看书的webapp, 这样在手机上看电子书很爽.找了好久发现发现只有追书神器的api暴露出来了,起点之类的api找不到. 同步:https://www.mwcxs.top/page/457 二.技术栈 vue2 + vuex + vue-router + webpack + ES

Vue-Router路由Vue-CLI脚手架和模块化开发 之 在单文件组件项目中定义数据、方法和组件之间的相互引用

定义数据 根据上一篇博文配置项目的结构的基础上继续进行优化: 在app.vue中的导出模块/组件部分设置其属性: export default{//导出模块/组件 data(){ return{ name:'perfect', count:0 } }, 在一个template标签中进行调用: <template> <div> <h2> 欢迎来到perfect*的博客园!!!</h2> <h3>{{name}}</h3> </te

【vue】vue-cli3构建项目中实现图片懒加载

前两天正好写了文章如何用实现图片懒加载[性能优化]JS实现图片懒加载,今天在使用vue构建项目的时候就遇到了要做图片懒加载的优化需要,本想把前两天的代码直接copy过来的,后来想查查看有没有更简便的方法,果不其然,vue中直接有插件可以使用,看了下实现时候的效果,实现原理都和原生js是一样的,vue果然真香! 接下来我们来讲vue-lazyload插件的使用: 1.安装插件 cnpm i vue-lazyload -S 2.入口文件main.js中配置: import Vue from 'vue

【JAVA】Java开发使用技巧_获取当前项目中某个文件路径

下面是一个小实例,注释也很清晰,但足以说明问题. 1.实例代码 1 public class TestMain { 2 3 public static String PROJECT_NAME = "/Test/"; 4 public static String FILE_NAME = "src/com/test/NewFile.xml"; 5 6 public static void main(String[] args) throws IOException {

vue的移动app项目中,自定义拖拽指令的问题

使用vue的都知道vue有一个自定义指令,我比较喜欢的就是拖拽的自定义指令,感觉挺方便的! //组件内的拖拽指令 directives: { //组建内自定义指令 drag: { // 指令的定义 bind: function(el, value) { let oDiv = el; //当前元素 let self = this; //上下文 oDiv.ontouchstart = function(e) { //鼠标按下,计算当前元素距离可视区的距离 let disX = e.touches[0

idea新手学习系列之创建maven web项目

idea开发系列教程(-)-创建maven webapp项目 可能大家在学习web的时候使用最多就是myeclipse和eclipse,我也是,我个人比较喜欢myeclipse,因为他会自加载xmlcatlog,eclipse貌似不会,每次我都得自己配置本地,但是作为向web进军的学习者,我们止步于ide的限制,作为开发者,我们不应该纠结于那种工具最好,那种是坨屎,我们应该关注的我们需要的功能,所以,不管那种工具,我们都有必要去了解一下,以下是我的学习心得: 1.首先安装idea,建议大家使用1

iOS开发系列--让你的应用“动”起来

--iOS核心动画 概览 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥iOS动画全貌.在这里你可以看到iOS中如何使用图层精简非交互式绘图,如何通过核心动画创建基础动画.关键帧动画.动画组.转场动画,如何通过UIView的装饰方法对这些动画操作进行简化等.在今天的文章里您可以看到动画操作在iOS中是如何简单和高效,很多原来想做但是苦于没有思路的动画在iOS中将变得越发简单: CALayer CALayer简介 CALayer常用属性 CALayer绘图 C

IOS开发系列 --- 核心动画

原始地址:http://www.cnblogs.com/kenshincui/p/3972100.html 概览 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥iOS动画全貌.在这里你可以看到iOS中如何使用图层精简非交互式绘图,如何通过核心动画创建基础动画.关键帧动画.动画组.转场动画,如何通过UIView的装饰方法对这些动画操作进行简化等.在今天的文章里您可以看到动画操作在iOS中是如何简单和高效,很多原来想做但是苦于没有思路的动画在iOS中将变得越发简