当前位置:   article > 正文

JWT的使用_jwt使用

jwt使用

目标:

①、jwt出现的原因及工作原理

②、jwt工具类介绍,三种场景

③、jwt与vuex配合在SPA项目中的应用

一、jwt的介绍

1、jwt是什么

JSON Web Token (JWT),它是目前最流行的跨域身份验证解决方案

2、为什么使用JWT

JWT的精髓在于:“去中心化”,数据是保存在客户端的。

3、JWT的工作原理

  1. 是在服务器身份验证之后,将生成一个JSON对象并将其发送回用户,示例如下: {"UserName": "Chongchong","Role": "Admin","Expire": "2018-08-08 20:15:56"}

  2. 之后,当用户与服务器通信时,客户在请求中发回JSON对象

  3. 为了防止用户篡改数据,服务器将在生成对象时添加签名,并对发回的数据进行验证

4、JWT组成


 一个JWT实际上就是一个字符串,它由三部分组成:头部(Header)、载荷(Payload)与签名(signature) JWT结构原理图:见资料“JWT的数据结构.jpg” JWT实际结构:eyJhbGciOiJIUzI1NiJ9. eyJzdWIiOiJ7fSIsImlzcyI6InpraW5nIiwiZXhwIjoxNTYyODUwMjM3LCJpYXQiOjE1NjI4NDg0MzcsImp0aSI6ImM5OWEyMzRmMDc4NzQyZWE4YjlmYThlYmYzY2VhNjBlIiwidXNlcm5hbWUiOiJ6c3MifQ. WUfqhFTeGzUZCpCfz5eeEpBXBZ8-lYg1htp-t7wD3I4

它是一个很长的字符串,中间用点(.)分隔成三个部分。注意,JWT 内部是没有换行的,这里只是为了便于展示,将它写成了几行。 写成一行,就是下面的样子:Header.Payload.Signature

二、jwt使用

web.xml

<!-- 解决jwt问题的过滤器 -->

<filter>
        <filter-name>jwtFilter</filter-name>
        <filter-class>com.zking.vue.util.JwtFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>jwtFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

将true改为false,开启 

JwtFilter 

     private boolean OFF = false;// true关闭jwt令牌验证功能

  1. package com.zking.vue.util;
  2. import java.io.IOException;
  3. import java.util.regex.Matcher;
  4. import java.util.regex.Pattern;
  5. import javax.servlet.Filter;
  6. import javax.servlet.FilterChain;
  7. import javax.servlet.FilterConfig;
  8. import javax.servlet.ServletException;
  9. import javax.servlet.ServletRequest;
  10. import javax.servlet.ServletResponse;
  11. import javax.servlet.http.HttpServletRequest;
  12. import javax.servlet.http.HttpServletResponse;
  13. import io.jsonwebtoken.Claims;
  14. /**
  15. * * JWT验证过滤器,配置顺序 :CorsFilte-->JwtFilter-->struts2中央控制器
  16. *
  17. * @author Administrator
  18. *
  19. */
  20. public class JwtFilter implements Filter {
  21. // 排除的URL,一般为登陆的URL(请改成自己登陆的URL)
  22. private static String EXCLUDE = "^/vue/userAction_login\\.action?.*$";
  23. private static Pattern PATTERN = Pattern.compile(EXCLUDE);
  24. private boolean OFF = false;// true关闭jwt令牌验证功能
  25. @Override
  26. public void init(FilterConfig filterConfig) throws ServletException {
  27. }
  28. @Override
  29. public void destroy() {
  30. }
  31. @Override
  32. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
  33. throws IOException, ServletException {
  34. HttpServletRequest req = (HttpServletRequest) request;
  35. HttpServletResponse resp = (HttpServletResponse) response;
  36. String path = req.getServletPath();
  37. if (OFF || isExcludeUrl(path)) {// 登陆直接放行
  38. chain.doFilter(request, response);
  39. return;
  40. }
  41. // 从客户端请求头中获得令牌并验证
  42. String jwt = req.getHeader(JwtUtils.JWT_HEADER_KEY);
  43. Claims claims = this.validateJwtToken(jwt);
  44. if (null == claims) {
  45. // resp.setCharacterEncoding("UTF-8");
  46. resp.sendError(403, "JWT令牌已过期或已失效");
  47. return;
  48. } else {
  49. String newJwt = JwtUtils.copyJwt(jwt, JwtUtils.JWT_WEB_TTL);
  50. resp.setHeader(JwtUtils.JWT_HEADER_KEY, newJwt);
  51. chain.doFilter(request, response);
  52. }
  53. }
  54. /**
  55. * 验证jwt令牌,验证通过返回声明(包括公有和私有),返回null则表示验证失败
  56. */
  57. private Claims validateJwtToken(String jwt) {
  58. Claims claims = null;
  59. try {
  60. if (null != jwt) {
  61. claims = JwtUtils.parseJwt(jwt);
  62. }
  63. } catch (Exception e) {
  64. e.printStackTrace();
  65. }
  66. return claims;
  67. }
  68. /**
  69. * 是否为排除的URL
  70. *
  71. * @param path
  72. * @return
  73. */
  74. private boolean isExcludeUrl(String path) {
  75. Matcher matcher = PATTERN.matcher(path);
  76. return matcher.matches();
  77. }
  78. // public static void main(String[] args) {
  79. // String path = "/sys/userAction_doLogin.action?username=zs&password=123";
  80. // Matcher matcher = PATTERN.matcher(path);
  81. // boolean b = matcher.matches();
  82. // System.out.println(b);
  83. // }
  84. }

userAction

将下面代码取消注释

Map<String, Object> claims = new HashMap<String, Object>();
                claims.put("uname",user.getUname());
                claims.put("pwd", user.getPwd());
                String jwt = JwtUtils.createJwt(claims, JwtUtils.JWT_WEB_TTL);
                response.setHeader(JwtUtils.JWT_HEADER_KEY, jwt);
                jsonData = new JsonData(1, "登录成功", u);

  1. package com.zking.vue.web;
  2. import java.util.HashMap;
  3. import java.util.Map;
  4. import com.fasterxml.jackson.databind.ObjectMapper;
  5. import com.opensymphony.xwork2.ModelDriven;
  6. import com.zking.base.web.BaseAction;
  7. import com.zking.vue.biz.UserBiz;
  8. import com.zking.vue.entity.User;
  9. import com.zking.vue.util.JsonData;
  10. import com.zking.vue.util.JwtUtils;
  11. import com.zking.vue.util.PageBean;
  12. import com.zking.vue.util.ResponseUtil;
  13. import com.zking.vue.util.StringUtils;
  14. public class UserAction extends BaseAction implements ModelDriven<User>{
  15. private UserBiz userBiz;
  16. private User user = new User();
  17. public UserBiz getUserBiz() {
  18. return userBiz;
  19. }
  20. public void setUserBiz(UserBiz userBiz) {
  21. this.userBiz = userBiz;
  22. }
  23. public String login() {
  24. ObjectMapper om = new ObjectMapper();
  25. JsonData jsonData = null;
  26. try {
  27. if(StringUtils.isBlank(user.getUname()) || StringUtils.isBlank(user.getPwd())) {
  28. jsonData = new JsonData(0, "用户或者密码为空", user);
  29. }else {
  30. User u = this.userBiz.login(user);
  31. Map<String, Object> claims = new HashMap<String, Object>();
  32. claims.put("uname",user.getUname());
  33. claims.put("pwd", user.getPwd());
  34. String jwt = JwtUtils.createJwt(claims, JwtUtils.JWT_WEB_TTL);
  35. response.setHeader(JwtUtils.JWT_HEADER_KEY, jwt);
  36. jsonData = new JsonData(1, "登录成功", u);
  37. }
  38. } catch (Exception e) {
  39. e.printStackTrace();
  40. jsonData = new JsonData(0, "用户或者密码错误", user);
  41. }finally {
  42. try {
  43. ResponseUtil.write(response, om.writeValueAsString(jsonData));
  44. } catch (Exception e) {
  45. e.printStackTrace();
  46. }
  47. }
  48. return null;
  49. }
  50. public String getAsyncData() {
  51. ObjectMapper om = new ObjectMapper();
  52. try {
  53. Thread.sleep(6000);
  54. ResponseUtil.write(response, om.writeValueAsString("http://www.javaxl.com"));
  55. } catch (Exception e) {
  56. e.printStackTrace();
  57. }
  58. return null;
  59. }
  60. @Override
  61. public User getModel() {
  62. return user;
  63. }
  64. }

界面不显示,报错403 

产生原因:

1、id被封,被拉入黑名单

2、没有登录凭证

在spa/src/api/http.js

// 响应拦截器
axios.interceptors.response.use(function(response) {
    debugger;
    var jwt = response.headers['jwt'];
    if(jwt){
        window.vm.$store.commit('setJwt',{jwt:jwt});
    }
    return response;
}, function(error) {
    return Promise.reject(error);
});

将jwt的值放入vuex中

main.js

增加红色部分

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
//开发环境下才会引入mockjs
//开发环境:true && require('@/mock')会执行后面的代码,也就是说mock.js会被导入到当前环境中
//生产环境:false  && require('@/mock')不会执行后面代码,也就是说mock.js不会引人到当前环境中
//  '/'相对的是src路径
// process.env.MOCK && require('@/mock')
import 'element-ui/lib/theme-chalk/index.css' //新添加2,避免后期打包样式不同,要放在import App from './App';之前
import App from './App'
import router from './router'
import ElementUI from 'element-ui' //新添加1

import axios from '@/api/http' // #vue项目对axios的全局配置
import VueAxios from 'vue-axios'
import store from './store'

Vue.use(ElementUI) //新添加3
Vue.use(VueAxios, axios)
Vue.config.productionTip = false

/* eslint-disable no-new */
window.vm= new Vue({
  el: '#app',
  data() {
    return {
      Bus: new Vue({

      })
    }
  },
  router,
  store,
  components: {
    App
  },
  template: '<App/>'
})

state.js

  1. export default{
  2.    resturantName:'飞歌餐馆',
  3. jwt:''
  4. }

 Mutations.js

  setJwt:(state,payload)=>{
    state.jwt=payload.jwt;
  },

  1. export default{
  2. setResturantName:(state,payload)=>{
  3. state.resturantName=payload.resturantName;
  4. },
  5. setJwt:(state,payload)=>{
  6. state.jwt=payload.jwt;
  7. },
  8. doAjax:(state,payload)=>{
  9. // 需求:想在当前的文件中与后台服务器做数据交互
  10. let _this=payload._this;
  11. let url = _this.axios.urls.SYSTEM_MENU_TREE;
  12. // 箭头函数解决了this 指针污染的问题
  13. _this.axios.post(url, {}).then((resp) => {
  14. console.log(resp);
  15. _this.menus=resp.data.result;
  16. }).catch(function(error) {
  17. console.log(error);
  18. });
  19. _this.$root.Bus.$on("collapsed-aside",(v)=>{
  20. _this.collapsed=v;
  21. });
  22. }
  23. }

Getters.js

getJwt:(state)=>{
    return state.jwt;
  }

  1. export default{
  2. getResturantName:(state)=>{
  3. return state.resturantName;
  4. },
  5. getJwt:(state)=>{
  6. return state.jwt;
  7. }
  8. }

http.js


// 请求拦截器
axios.interceptors.request.use(function(config) {
    var jwt = window.vm.$store.getters.getJwt;
    config.headers['jwt'] = jwt;
    return config;
}, function(error) {
    return Promise.reject(error);
});

// 响应拦截器
axios.interceptors.response.use(function(response) {
    debugger;
    var jwt = response.headers['jwt'];
    if(jwt){
        window.vm.$store.commit('setJwt',{jwt:jwt});
    }
    return response;
}, function(error) {
    return Promise.reject(error);
});

登录后界面显示 

 三、三种场景

     三种场景及结果展示

第一个:是怎么通过jwt工具类去生成jwt令牌和解析jwt令牌;

用户信息都获得了,签发过期时间都出现了

 第二个:jwt令牌过期场景

以下错误就是令牌过期:

第三个:延续令牌的存活时间 

令牌过期时间为30分钟,假如一直在使用,30分钟后就要过期(不合理),

因此,需要设置最后使用时间为签发时间,再过30分钟为过期时间

解决方法:copy  jwt令牌,从新设置签发过期时间

 代码:

  1. package com.zking.vue.test;
  2. import java.text.SimpleDateFormat;
  3. import java.util.Date;
  4. import java.util.HashMap;
  5. import java.util.Map;
  6. import org.junit.Test;
  7. import com.zking.vue.util.JwtUtils;
  8. import io.jsonwebtoken.Claims;
  9. public class JwtDemo {
  10. private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
  11. @Test
  12. public void test1() {// 生成JWT
  13. Map<String, Object> claims = new HashMap<String, Object>();
  14. claims.put("username", "zss");
  15. claims.put("age", 18);
  16. String jwt = JwtUtils.createJwt(claims, JwtUtils.JWT_WEB_TTL);
  17. System.out.println(jwt);
  18. Claims parseJwt = JwtUtils.parseJwt(jwt);
  19. for (Map.Entry<String, Object> entry : parseJwt.entrySet()) {
  20. System.out.println(entry.getKey() + "=" + entry.getValue());
  21. }
  22. Date d1 = parseJwt.getIssuedAt();
  23. Date d2 = parseJwt.getExpiration();
  24. System.out.println("令牌签发时间:" + sdf.format(d1));
  25. System.out.println("令牌过期时间:" + sdf.format(d2));
  26. }
  27. @Test
  28. public void test2() {// 解析oldJwt
  29. // String oldJwt = "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NjI5MDMzNjAsImlhdCI6MTU2MjkwMTU2MCwiYWdlIjoxOCwianRpIjoiZDVjMzE4Njg0MDcyNDgyZDg1MDE5ODVmMDY3OGQ4NjkiLCJ1c2VybmFtZSI6InpzcyJ9.XDDDRRq5jYq5EdEBHtPm7GcuBz4S0VhDTS1amRCdf48";
  30. String oldJwt = "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NjM1MjU5MjMsImlhdCI6MTU2MzUyNDEyMywiYWdlIjoxOCwianRpIjoiOTAzNmMwY2Q3NGIwNDBjMzgzMDAxYzdiNmZkMzYzZmIiLCJ1c2VybmFtZSI6InpzcyJ9.sgV9fr4fgmmahDFRJnsfazA6R3H-gNMVcg2ucA227n4";
  31. Claims parseJwt = JwtUtils.parseJwt(oldJwt);
  32. for (Map.Entry<String, Object> entry : parseJwt.entrySet()) {
  33. System.out.println(entry.getKey() + "=" + entry.getValue());
  34. }
  35. Date d1 = parseJwt.getIssuedAt();
  36. Date d2 = parseJwt.getExpiration();
  37. System.out.println("令牌签发时间:" + sdf.format(d1));
  38. System.out.println("令牌过期时间:" + sdf.format(d2));
  39. }
  40. @Test
  41. public void test3() {// 复制jwt,并延时30
  42. String oldJwt = "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NjI5MDMzNjAsImlhdCI6MTU2MjkwMTU2MCwiYWdlIjoxOCwianRpIjoiZDVjMzE4Njg0MDcyNDgyZDg1MDE5ODVmMDY3OGQ4NjkiLCJ1c2VybmFtZSI6InpzcyJ9.XDDDRRq5jYq5EdEBHtPm7GcuBz4S0VhDTS1amRCdf48";
  43. String jwt = JwtUtils.copyJwt(oldJwt, JwtUtils.JWT_WEB_TTL);
  44. Claims parseJwt = JwtUtils.parseJwt(jwt);
  45. for (Map.Entry<String, Object> entry : parseJwt.entrySet()) {
  46. System.out.println(entry.getKey() + "=" + entry.getValue());
  47. }
  48. Date d1 = parseJwt.getIssuedAt();
  49. Date d2 = parseJwt.getExpiration();
  50. System.out.println("令牌签发时间:" + sdf.format(d1));
  51. System.out.println("令牌过期时间:" + sdf.format(d2));
  52. }
  53. @Test
  54. public void test4() {// 测试JWT的有效时间
  55. Map<String, Object> claims = new HashMap<String, Object>();
  56. claims.put("username", "zss");
  57. String jwt = JwtUtils.createJwt(claims, 3 * 1000L);
  58. System.out.println(jwt);
  59. Claims parseJwt = JwtUtils.parseJwt(jwt);
  60. Date d1 = parseJwt.getIssuedAt();
  61. Date d2 = parseJwt.getExpiration();
  62. System.out.println("令牌签发时间:" + sdf.format(d1));
  63. System.out.println("令牌过期时间:" + sdf.format(d2));
  64. }
  65. @Test
  66. public void test5() {// 三秒后再解析上面过期时间只有三秒的令牌,因为过期则会报错io.jsonwebtoken.ExpiredJwtException
  67. String oldJwt = "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NjI4NTMzMzAsImlhdCI6MTU2Mjg1MzMyNywidXNlcm5hbWUiOiJ6c3MifQ.e098Vj9KBlZfC12QSDhI5lUGRLbNwb27lrYYSL6JwrQ";
  68. Claims parseJwt = JwtUtils.parseJwt(oldJwt);
  69. // 过期后解析就报错了,下面代码根本不会执行
  70. Date d1 = parseJwt.getIssuedAt();
  71. Date d2 = parseJwt.getExpiration();
  72. System.out.println("令牌签发时间:" + sdf.format(d1));
  73. System.out.println("令牌过期时间:" + sdf.format(d2));
  74. }

-----------------没有了------------------------------------------------

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/544509
推荐阅读
相关标签
  

闽ICP备14008679号