我的编程空间,编程开发者的网络收藏夹
学习永远不晚

如何进行SpringBoot整合JWT的实现

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

如何进行SpringBoot整合JWT的实现

这篇文章跟大家分析一下“如何进行SpringBoot整合JWT的实现”。内容详细易懂,对“如何进行SpringBoot整合JWT的实现”感兴趣的朋友可以跟着小编的思路慢慢深入来阅读一下,希望阅读后能够对大家有所帮助。下面跟着小编一起深入学习“如何进行SpringBoot整合JWT的实现”的知识吧。

一. JWT简介

1. 什么是JWT?

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

它将用户信息加密到token里,服务器不保存任何用户信息。服务器通过使用保存的密钥验证token的正确性,只要正确即通过验证;应用场景如用户登录。JWT详细讲解请见 github:https://github.com/jwtk/jjwt

2. 为什么使用JWT?

随着技术的发展,分布式web应用的普及,通过session管理用户登录状态成本越来越高,因此慢慢发展成为token的方式做登录身份校验,然后通过token去取redis中的缓存的用户信息,随着之后jwt的出现,校验方式更加简单便捷化,无需通过redis缓存,而是直接根据token取出保存的用户信息,以及对token可用性校验,单点登录更为简单。

3. 传统Cookie+Session与JWT对比

① 在传统的用户登录认证中,因为http是无状态的,所以都是采用session方式。用户登录成功,服务端会保证一个session,当然会给客户端一个sessionId,客户端会把sessionId保存在cookie中,每次请求都会携带这个sessionId。

cookie+session这种模式通常是保存在内存中,而且服务从单服务到多服务会面临的session共享问题,随着用户量的增多,开销就会越大。而JWT不是这样的,只需要服务端生成token,客户端保存这个token,每次请求携带这个token,服务端认证解析就可。

② JWT方式校验方式更加简单便捷化,无需通过redis缓存,而是直接根据token取出保存的用户信息,以及对token可用性校验,单点登录,验证token更为简单。

4. JWT的组成(3部分)

第一部分为头部(header),第二部分我们称其为载荷(payload),第三部分是签证(signature)。【中间用 . 分隔】

一个标准的JWT生成的token格式如下:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJzdWIiOiI1IiwiaWF0IjoxNTY1NTk3MDUzLCJleHAiOjE1NjU2MDA2NTN9.qesdk6aeFEcNafw5WFm-TwZltGWb1Xs6oBEk5QdaLzlHxDM73IOyeKPF_iN1bLvDAlB7UnSu-Z-Zsgl_dIlPiw

5. JWT验证流程和特点

验证流程:

① 在头部信息中声明加密算法和常量, 然后把header使用json转化为字符串
② 在载荷中声明用户信息,同时还有一些其他的内容;再次使用json 把载荷部分进行转化,转化为字符串
③ 使用在header中声明的加密算法和每个项目随机生成的secret来进行加密, 把第一步分字符串和第二部分的字符串进行加密, 生成新的字符串。词字符串是独一无二的。
④ 解密的时候,只要客户端带着JWT来发起请求,服务端就直接使用secret进行解密。

特点:

① 三部分组成,每一部分都进行字符串的转化
② 解密的时候没有使用数据库,仅仅使用的是secret进行解密
③ JWT的secret千万不能泄密!

6. JWT优缺点

优点:

①. 可扩展性好

应用程序分布式部署的情况下,Session需要做多机数据共享,通常可以存在数据库或者Redis里面。而JWT不需要。

②. 无状态

JWT不在服务端存储任何状态。RESTful API的原则之一是无状态,发出请求时,总会返回带有参数的响应,不会产生附加影响。用户的认证状态引入这种附加影响,这破坏了这一原则。另外JWT的载荷中可以存储一些常用信息,用于交换信息,有效地使用 JWT,可以降低服务器查询数据库的次数。

缺点:

① 安全性:由于JWT的payload是使用Base64编码的,并没有加密,因此JWT中不能存储敏感数据。而Session的信息是存在服务端的,相对来说更安全。

② 性能:JWT太长。由于是无状态使用JWT,所有的数据都被放到JWT里,如果还要进行一些数据交换,那载荷会更大,经过编码之后导致JWT非常长,Cookie的限制大小一般是4k,cookie很可能放不下,所以JWT一般放在LocalStorage里面。并且用户在系统中的每一次Http请求都会把JWT携带在Header里面,Http请求的Header可能比Body还要大。而SessionId只是很短的一个字符串,因此使用JWT的Http请求比使用Session的开销大得多。

③ 一次性:无状态是JWT的特点,但也导致了这个问题,JWT是一次性的。想修改里面的内容,就必须签发一个新的JWT。即缺陷是一旦下发,服务后台无法拒绝携带该jwt的请求(如踢除用户)

(1)无法废弃:通过JWT的验证机制可以看出来,一旦签发一个JWT,在到期之前就会始终有效,无法中途废弃。例如你在payload中存储了一些信息,当信息需要更新时,则重新签发一个JWT,但是由于旧的jwt还没过期,拿着这个旧的JWT依旧可以登录,那登录后服务端从JWT中拿到的信息就是过时的。为了解决这个问题,我们就需要在服务端部署额外的逻辑,例如设置一个黑名单,一旦签发了新的JWT,那么旧的就加入黑名单(比如存到redis里面),避免被再次使用。

(2)续签:如果你使用jwt做会话管理,传统的Cookie续签方案一般都是框架自带的,Session有效期30分钟,30分钟内如果有访问,有效期被刷新至30分钟。一样的道理,要改变JWT的有效时间,就要签发新的JWT。最简单的一种方式是每次请求刷新JWT,即每个HTTP请求都返回一个新的JWT。这个方法不仅暴力不优雅,而且每次请求都要做JWT的加密解密,会带来性能问题。另一种方法是在Redis中单独为每个JWT设置过期时间,每次访问时刷新JWT的过期时间。

可以看出想要破解JWT一次性的特性,就需要在服务端存储jwt的状态。但是引入 redis 之后,就把无状态的jwt硬生生变成了有状态了,违背了JWT的初衷。而且这个方案和Session都差不多了。

二. Java实现JWT(SpringBoot方式整合)

 1. Maven依赖与application.yml配置

<!-- JWT依赖 --><dependency>    <groupId>io.jsonwebtoken</groupId>    <artifactId>jjwt</artifactId>    <version>0.7.0</version></dependency><dependency>    <groupId>com.auth0</groupId>    <artifactId>java-jwt</artifactId>    <version>3.4.0</version></dependency>
server:  port: 8080spring:  application:    name: springboot-jwtconfig:  jwt:    # 加密密钥    secret: abcdefg1234567    # token有效时长    expire: 3600    # header 名称    header: token

 2. 编写JwtConfig

package com.example.config; import io.jsonwebtoken.Claims;import io.jsonwebtoken.Jwts;import io.jsonwebtoken.SignatureAlgorithm;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.stereotype.Component;import java.util.Date; @ConfigurationProperties(prefix = "config.jwt")@Componentpublic class JwtConfig {     private String secret;    private long expire;    private String header;         public String createToken (String subject){        Date nowDate = new Date();        Date expireDate = new Date(nowDate.getTime() + expire * 1000);//过期时间         return Jwts.builder()                .setHeaderParam("typ", "JWT")                .setSubject(subject)                .setIssuedAt(nowDate)                .setExpiration(expireDate)                .signWith(SignatureAlgorithm.HS512, secret)                .compact();    }        public Claims getTokenClaim (String token) {        try {            return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();        }catch (Exception e){//            e.printStackTrace();            return null;        }    }        public boolean isTokenExpired (Date expirationTime) {        return expirationTime.before(new Date());    }         public Date getExpirationDateFromToken(String token) {        return getTokenClaim(token).getExpiration();    }        public String getUsernameFromToken(String token) {        return getTokenClaim(token).getSubject();    }         public Date getIssuedAtDateFromToken(String token) {        return getTokenClaim(token).getIssuedAt();    }     // --------------------- getter & setter ---------------------     public String getSecret() {        return secret;    }    public void setSecret(String secret) {        this.secret = secret;    }    public long getExpire() {        return expire;    }    public void setExpire(long expire) {        this.expire = expire;    }    public String getHeader() {        return header;    }    public void setHeader(String header) {        this.header = header;    }}

 3. 配置拦截器

package com.example.interceptor; import com.example.config.JwtConfig;import io.jsonwebtoken.Claims;import io.jsonwebtoken.SignatureException;import org.springframework.stereotype.Component;import org.springframework.util.StringUtils;import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import javax.annotation.Resource;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse; @Componentpublic class TokenInterceptor extends HandlerInterceptorAdapter {     @Resource    private JwtConfig jwtConfig ;    @Override    public boolean preHandle(HttpServletRequest request,                             HttpServletResponse response,                             Object handler) throws SignatureException {                String uri = request.getRequestURI() ;        if (uri.contains("/login")){            return true ;        }                String token = request.getHeader(jwtConfig.getHeader());        if(StringUtils.isEmpty(token)){            token = request.getParameter(jwtConfig.getHeader());        }        if(StringUtils.isEmpty(token)){            throw new SignatureException(jwtConfig.getHeader()+ "不能为空");        }         Claims claims = null;        try{            claims = jwtConfig.getTokenClaim(token);            if(claims == null || jwtConfig.isTokenExpired(claims.getExpiration())){                throw new SignatureException(jwtConfig.getHeader() + "失效,请重新登录。");            }        }catch (Exception e){            throw new SignatureException(jwtConfig.getHeader() + "失效,请重新登录。");        }                 request.setAttribute("identityId", claims.getSubject());        return true;    }}

  注册拦截器到SpringMvc

package com.example.config; import com.example.interceptor.TokenInterceptor;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import javax.annotation.Resource; @Configurationpublic class WebConfig implements WebMvcConfigurer {    @Resource    private TokenInterceptor tokenInterceptor ;    public void addInterceptors(InterceptorRegistry registry) {        registry.addInterceptor(tokenInterceptor).addPathPatterns("    @PostMapping("/login")    public ResultBO<?> login (@RequestParam("userName") String userName,                           @RequestParam("passWord") String passWord){        JSONObject json = new JSONObject();                  // 这里模拟通过用户名和密码,从数据库查询userId        // 这里把userId转为String类型,实际开发中如果subject需要存userId,则可以JwtConfig的createToken方法的参数设置为Long类型        String userId = 5 + "";        String token = jwtConfig.createToken(userId) ;        if (!StringUtils.isEmpty(token)) {            json.put("token",token) ;        }        return ResultTool.success(json) ;    }         @PostMapping("/info")    public ResultBO<?> info (){        return ResultTool.success("info") ;    }         @GetMapping("/getUserInfo")    public ResultBO<?> getUserInfo(HttpServletRequest request){        String usernameFromToken = jwtConfig.getUsernameFromToken(request.getHeader("token"));        return ResultTool.success(usernameFromToken) ;    }      }

用PostMan测试工具测试一下,访问登录接口,当对账号密码验证通过时,则返回一个token给客户端:

如何进行SpringBoot整合JWT的实现

 当直接去访问info接口时,会返回token为空的自定义异常:

如何进行SpringBoot整合JWT的实现

 当在请求头加上正确token时,则拦截器验证通过,可以正常访问到接口:

如何进行SpringBoot整合JWT的实现

 当在请求头加入一个错误token,则会返回token失效的自定义异常:

如何进行SpringBoot整合JWT的实现

 接下来测试一下获取用户信息,因为这里存的subject为userId,所以直接返回上面写死的假数据5:

如何进行SpringBoot整合JWT的实现

JWT

基于JSON,所以JWT是可以进行跨语言支持的,像JAVA,JavaScript,Node.JS,PHP等很多语言都可以使用。

payload部分,需要时JWT可以存储一些其他业务逻辑所必要的非敏感信息。

体积小巧,便于传输;JWT的构成非常简单,字节占用很小,所以它是非常便于传输的。它不需要在服务端保存会话信息, 所以它易于应用的扩展。

关于如何进行SpringBoot整合JWT的实现就分享到这里啦,希望上述内容能够让大家有所提升。如果想要学习更多知识,请大家多多留意小编的更新。谢谢大家关注一下编程网网站!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

如何进行SpringBoot整合JWT的实现

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

如何进行SpringBoot整合JWT的实现

这篇文章跟大家分析一下“如何进行SpringBoot整合JWT的实现”。内容详细易懂,对“如何进行SpringBoot整合JWT的实现”感兴趣的朋友可以跟着小编的思路慢慢深入来阅读一下,希望阅读后能够对大家有所帮助。下面跟着小编一起深入学习
2023-06-26

JWT如何整合Springboot

这篇文章将为大家详细讲解有关JWT如何整合Springboot,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1.基于JWT认证1.1 认证流程首先,前端通过Web表单将自己的用户名和密码发送到后端的接口。
2023-06-21

使用springboot如何实现对freemarker进行整合

这篇文章将为大家详细讲解有关使用springboot如何实现对freemarker进行整合,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。前提:开发工具:idea框架:spring boot、
2023-05-31

使用springboot如何实现对 beatlsql进行整合

这篇文章给大家介绍使用springboot如何实现对 beatlsql进行整合,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。BeetSql是一个全功能DAO工具, 同时具有hibernate 优点 & Mybatis优
2023-05-31

使用SpringBoot如何实现对ElasticSearch进行整合

这篇文章给大家介绍使用SpringBoot如何实现对ElasticSearch进行整合,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。一、实体设计:Tutorial.javapublic class Tutorial i
2023-05-31

使用springboot如何实现对mongodb进行整合

使用springboot如何实现对mongodb进行整合?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。环境依赖在pom文件引入spring-boot-starter-data-
2023-05-31

如何进行SpringBoot 整合JPA

如何进行SpringBoot 整合JPA,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。JPA全称Java Persistence API.JPA通过JDK 5.
2023-06-05

springboot如何进行整合mongodb

springboot如何进行整合mongodb,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。准备工作安装 MongoDBjdk 1.8maven 3.0idea环境依赖在p
2023-06-19

利用Android如何实现对 ToolBar进行整合

本篇文章给大家分享的是有关利用Android如何实现对 ToolBar进行整合,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。CustomeToolBar继承原生ToolBarp
2023-05-31

使用Spring4如何实现对Hibernate5进行整合

使用Spring4如何实现对Hibernate5进行整合?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Spring与Hiberante整合通过hibernate
2023-05-31

springboot整合websocket如何实现群聊

这篇文章将为大家详细讲解有关springboot整合websocket如何实现群聊,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。实现思路发送者向服务器发送大家早上好。其它客户端可以收到对应消息。项目展示通
2023-06-15

使用spring boot如何实现对CAS进行整合

今天就跟大家聊聊有关使用spring boot如何实现对CAS进行整合,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。代码整合cas的重要过程import org.jasig.cas.
2023-05-31

使用spring boot如何实现对Swagger2进行整合

本篇文章给大家分享的是有关使用spring boot如何实现对Swagger2进行整合,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Swagger 是一个规范和完整的框架,用于
2023-05-31

使用spring boot如何实现对RabbitMQ进行整合

使用spring boot如何实现对RabbitMQ进行整合?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。springboot集成RabbitMQ非常简单,如果
2023-05-31

使用Spring Boot如何实现对MongoDB进行整合

本篇文章给大家分享的是有关使用Spring Boot如何实现对MongoDB进行整合,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。MongoDB是什么?MongoDB是一个No
2023-05-31

使用spring如何实现springmvc与mybatis进行整合

使用spring如何实现springmvc与mybatis进行整合?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。1.jar包 2.引入web.xml文件
2023-05-31

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录