zoukankan      html  css  js  c++  java
  • 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。

  • 相关阅读:
    POJ——T2186 Popular Cows || 洛谷——P2341 [HAOI2006]受欢迎的牛
    Tarjan缩点【模板】
    shell(1):网络配置、BATH环境和通配符
    STL
    J
    H
    G
    模板整理(二)
    B
    0-1背包问题
  • 原文地址:https://www.cnblogs.com/chengxs/p/10010303.html
Copyright © 2011-2022 走看看