资讯专栏INFORMATION COLUMN

songEagle开发系列:Vue + Vuex + Koa 中使用JWT认证

suosuopuo / 661人阅读

摘要:一前言,是为了在网络环境间传递声明而执行的一种基于的开放标准。用户签发添加中间件校验判断是否可用获取解密,获取用户名和认证失败中添加处理此处在开发时需要过滤掉登录接口,否则会导致验证永远失败。前端处理前端开发使用的是,发送请求使用的是。

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

JWT不是一个新鲜的东西,网上相关的介绍已经非常多了。不是很了解的可以在网上搜索一下相关信息。
同步到sau交流学习社区:https://www.mwcxs.top/page/45...

二、源码

Talk is cheap. Show me the code.

三、工作流程

JWT本质来说是一个token。在前后端进行HTTP连接时来进行相应的验证。

博客的后台管理系统发起登录请求,后端服务器校验成功之后,生成JWT认证信息;

前端接收到JWT后进行存储;

前端在之后每次接口调用发起HTTP请求时,会将JWT放到HTTP的headers参数里的authorization中一起发送给后端;

后端接收到请求时会根据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/son...

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

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/99358.html

相关文章

  • 关于Vue2一些值得推荐的文章 -- 五、六月份

    摘要:五六月份推荐集合查看最新的请点击集前端最近很火的框架资源定时更新,欢迎一下。苏幕遮燎沈香宋周邦彦燎沈香,消溽暑。鸟雀呼晴,侵晓窥檐语。叶上初阳乾宿雨,水面清圆,一一风荷举。家住吴门,久作长安旅。五月渔郎相忆否。小楫轻舟,梦入芙蓉浦。 五、六月份推荐集合 查看github最新的Vue weekly;请::点击::集web前端最近很火的vue2框架资源;定时更新,欢迎 Star 一下。 苏...

    sutaking 评论0 收藏0
  • 关于Vue2一些值得推荐的文章 -- 五、六月份

    摘要:五六月份推荐集合查看最新的请点击集前端最近很火的框架资源定时更新,欢迎一下。苏幕遮燎沈香宋周邦彦燎沈香,消溽暑。鸟雀呼晴,侵晓窥檐语。叶上初阳乾宿雨,水面清圆,一一风荷举。家住吴门,久作长安旅。五月渔郎相忆否。小楫轻舟,梦入芙蓉浦。 五、六月份推荐集合 查看github最新的Vue weekly;请::点击::集web前端最近很火的vue2框架资源;定时更新,欢迎 Star 一下。 苏...

    khs1994 评论0 收藏0

发表评论

0条评论

suosuopuo

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<