前后端分离之JWT(JSON Web Token)的使用

52

前言

由于自己开发的项目中用到了 JWT 技术,前端采用了 Vue.js 框架,后端采用了 CodeIgniter 框架,故作此文帮助使用相同技术栈的朋友们。

具体思路如下:
把后端生成的 JWT token 存入 localStorage,然后前端切换路由(刷新页面)的时候,通过 Ajax 请求的时候带上这个 token,提交给后端判断当前的 token 是否有效,后端返回结果。

JWT 用处很多,可以用于后台权限的限制、接口安全性校验。

使用教程

前端 Vue.js

vue-router

登录时,将后端返回的 token 存入 localStorage

使用 Vue-Router 判断是否存在 token,不存在跳转至登录

// JWT 用户权限校验,判断 TOKEN 是否在 localStorage 当中
router.beforeEach(({name}, from, next) => {
  // 获取 JWT Token
  if (localStorage.getItem('JWT_TOKEN')) {
    // 如果用户在login页面
    if (name === 'login') {
      next('/');
    } else {
      next();
    }
  } else {
    if (name === 'login') {
      next();
    } else {
      next({name: 'login'});
    }
  }
});

axios

axios 全局配置拦截器
每次向后端请求携带 头信息

src/main.js 当中加上以下代码:

// http request 拦截器
axios.interceptors.request.use(
  config => {
    if (localStorage.JWT_TOKEN) {  // 判断是否存在token,如果存在的话,则每个http header都加上token
      config.headers.Authorization = `token ${localStorage.JWT_TOKEN}`;
    }
    return config;
  },
  err => {
    return Promise.reject(err);
  });

// http response 拦截器
axios.interceptors.response.use(
  response => {
    return response;
  },
  error => {
    if (error.response) {
      console.log('axios:' + error.response.status);
      switch (error.response.status) {
        case 401:
          // 返回 401 清除token信息并跳转到登录页面
          store.commit('LOG_OUT');
          router.replace({
            path: 'login',
            query: {redirect: router.currentRoute.fullPath}
          });
      }
    }
    return Promise.reject(error.response.data);   // 返回接口返回的错误信息
  });

Vue.prototype.$http = axios;

后端 CodeIgniter

后端 Controller 接收请求头信息,验证 token 有效性,无效返回 401 状态码

    $header = $this->input->get_request_header('Authorization', TRUE); // 获取请求头 Authorization
    list($token) = sscanf($header, 'token %s'); // 提取 token
    if ($header != '' && jwt_helper::validate($token)) {
        $userid = jwt_helper::decode($header)->userId; // 解码token 提取 userId 字段
        // do something
    } else {
        show_error("Permission denied", 401, "Please check your token."); // 401错误
    }
这里提供了自己使用的封装好的 JWT Helper 类 和 JWT 的库 使用方法和文件可以访问 Github
仓库:https://github.com/52admln/JW...

安全性

可参考文章:http://www.cnblogs.com/xiekel... 当中的基于JWT的Token认证的安全问题


如果觉得我的文章对你有用,请随意赞赏

你可能感兴趣的

29 条评论
摇篮进行曲 · 2017年08月01日

我想问一下如果恶意用户从浏览器获取到jwt再用postman之类的工具模拟是否能成功?

+9 回复

4

@摇篮进行曲 可以啊,都是个http请求

Salamander · 2017年08月01日
6

可以请求

52admln 作者 · 2017年08月01日
3

用 Vue 的话可以把 token 存在 store 里面,或者将 token 加密一下。

52admln 作者 · 2017年08月01日
拳风 · 2017年08月04日

token过期怎么处理的?

回复

1

token 过期时间可自己配置,通过 JWT 库判断过期后,后端返回 401 错误码 或其它错误,前端进行判断并执行相应操作如重新登录等。

52admln 作者 · 2017年08月04日
0

@52admln token 过期后应该要刷新token重新获取吧,直接401错误重新登录不合理啊.

九天 · 2017年12月19日
0

过期判断我在repo里更新了。

52admln 作者 · 2017年12月20日
Cheng · 2017年08月09日

上面的代码vue router的beforEach钩子中,每次导航都判断localStorage的token是否存在,而没有经过后端的token验证,是否意味着用户只要登录过一次,尽管token过期但只要不发送请求,就不限制页面的跳转了?

回复

0

是的,为了安全可以做后端的校验。

52admln 作者 · 2017年08月09日
0

@52admln 我正在做这个东西,然后学习了你的文章把前面都搞定了,只是这里出现了疑惑。我的想法是在vue router导航钩子中加入一个请求,只要不是go login,其他的都先走这个请求验证token,如果token验证失败或时间过期就跳转至login,向你请教一下这种思路是否可行,有什么安全性的漏洞吗?感谢回复

Cheng · 2017年08月09日
0

@菜的没边了 可以的。

52admln 作者 · 2017年08月11日
Sweet_KK · 2018年05月16日

可以存储到cookie么,因为每次请求都会带上,这样还省了一个全局拦截设置请求头的步骤,后端直接拿到请求的cookie判断就好了

回复

0

可以的。

52admln 作者 · 2018年05月17日
0

我开始也是这样写的,公司大佬告诉我这样,现在是没有问题的,但是以后业务扩展的,可能有跨域请求的问题,然后我就改成楼主的方式了

king_ran · 3月4日
louis · 2018年05月23日

你好 我尝试在router.beforeEach 中使用 localStorage 但他却是 undefined

回复

简单7月 · 2018年07月03日

如果token失效了,返回401后,你又是怎么处理的呢?

回复

0

我是前端进行登录跳转的。

52admln 作者 · 2018年07月05日
载入中...