深入总结SpringBoot整合JWT,这应该是全网讲的最通俗易懂的了

Hello friends social networking, on this occasion the admin wants to share an article entitled 深入总结SpringBoot整合JWT,这应该是全网讲的最通俗易懂的了 , we have made good, quality and useful articles for you to read and take information in. hopefully the post content is about which we write you can understand. Alright, happy reading.
我们都知道JWT是一个JSON信息传输的开放标准,它可以使用密钥对信息进行数字签名,以确保信息是可验证和可信任的。今天我们来深入总结SpringBoot整合JWT

前言

我们都知道JWT是一个JSON信息传输的开放标准,它可以使用密钥对信息进行数字签名,以确保信息是可验证和可信任的。今天我们来深入总结SpringBoot整合JWT

举例登录过程

image

认证流程

  1. 首先,前端通过Web表单将自己的用户名和密码发送到后端的接口。这一过程一般是一个HTTP POST请求。建议的方式是通过SSL加密的传输(https协议) ,从而避免敏感信息被嗅探。
  2. 后端核对用户名和密码成功后,将用户的id等其他信息作为JWT Payload (负载) ,将其与头部分别进行Base64编码拼接后签名,形成一个JWT(Token)。形成的JWT就是一 个形同111.zzz . xxx的字符串。 token head. payload . singurater
  3. 后端将JWT字符串作为登录成功的返回结果返回给前端。前端可以将返回的结果保存在localStor age或sessionStorage上,退出登录时前端删除保存的JWT即可。
  4. 前端在每次请求时将JWT放入HTTP Header中的Authorization位。 (解决XSS和XSRF问题) HEADER
  5. 后端检查是否存在,如存在验证JWT的有效性。例如,检查签名是否正确;检查Token是否过期;检查Token的接收方是否是自己(可选)
  6. 验证通过后后端使用JWT中包含的用户信息进行其他逻辑操作,返回相应结果。

jwt优势

  • 不需要在服务端保存会话信息,特别适用于分布式微服务。
  • 自包含(Self-contained):负载中包含了所有用户所需要的信息,避免了多次查询数据库
  • 简洁(Compact):可以通过URL, POST参数或者在HTTP header发送,因为数据量小,传输速度也很快
  • 因为Token是以JSON加密的形式保存在客户端的,所以JWT是跨语言的,原则上任何web形式都支持。

组成

JWT具体长什么样呢? JWT是由三段信息构成的,将这三段信息文本用.链接在一起就构成了JWT字符串。就像这样:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

结构

JWT的头部承载两部分信息:

  • 声明类型,这里是JWT;
  • 声明加密的算法,通常直接使用 HMAC SHA256;
  • 完整的头部就像下面这样的JSON:
{ 'typ': 'JWT', 'alg': 'HS256'}

使用base64加密,构成了第一部分。

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

playload(重点)

载荷就是存放有效信息的地方,这些有效信息包含三个部分:

  • 标准中注册的声明;
  • 公共的声明;
  • 私有的声明;

其中,标准中注册的声明 (建议但不强制使用)包括如下几个部分 :

  • iss: jwt签发者;
  • sub: jwt所面向的用户;
  • aud: 接收jwt的一方;
  • exp: jwt的过期时间,这个过期时间必须要大于签发时间;
  • nbf: 定义在什么时间之前,该jwt都是不可用的;
  • iat: jwt的签发时间;
  • jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击;

公共的声明部分:公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息,但不建议添加敏感信息,因为该部分在客户端可解密。

私有的声明部分:私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。

定义一个payload:

{ "sub": "1234567890", "name": "John Doe", "admin": true}

然后将其进行base64加密,得到Jwt的第二部分:

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

signature

jwt的第三部分是一个签证信息,这个签证信息由三部分组成:

var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload); var signature = HMACSHA256(encodedString, '密钥');加密之后,得到signature签名信息。TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

jwt最终格式

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

secret用来进行jwt的签发和jwt的验证,所以,在任何场景都不应该流露出去。

SpringBoot整合JWT【正片】

引入依赖

<!--token--> <!-- jwt支持 --> <dependency>  <groupId>com.auth0</groupId>  <artifactId>java-jwt</artifactId> </dependency>

创建JWT工具类

注意静态属性的配置文件注入方式:

package com.neuq.common.util;import com.auth0.jwt.JWT;import com.auth0.jwt.algorithms.Algorithm;import com.auth0.jwt.exceptions.TokenExpiredException;import com.neuq.common.exception.ApiException;import com.neuq.common.response.ResultInfo;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.stereotype.Component;import java.util.Date;/** * @Author: xiang * @Date: 2021/5/11 21:11 * <p> * JwtToken生成的工具类 * JWT token的格式:header.payload.signature * header的格式(算法、token的类型),默认:{"alg": "HS512","typ": "JWT"} * payload的格式 设置:(用户信息、创建时间、生成时间) * signature的生成算法: * HMACSHA512(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret) */@Component@ConfigurationProperties(prefix = "jwt")public class JWTUtils { //定义token返回头部 public static String header; //token前缀 public static String tokenPrefix; //签名密钥 public static String secret; //有效期 public static long expireTime; //存进客户端的token的key名 public static final String USER_LOGIN_TOKEN = "USER_LOGIN_TOKEN"; public void setHeader(String header) {  JWTUtils.header = header; } public void setTokenPrefix(String tokenPrefix) {  JWTUtils.tokenPrefix = tokenPrefix; } public void setSecret(String secret) {  JWTUtils.secret = secret; } public void setExpireTime(int expireTimeInt) {  JWTUtils.expireTime = expireTimeInt*1000L*60; } /**  * 创建TOKEN  * @param sub  * @return  */ public static String createToken(String sub){  return tokenPrefix + JWT.create()    .withSubject(sub)    .withExpiresAt(new Date(System.currentTimeMillis() + expireTime))    .sign(Algorithm.HMAC512(secret)); } /**  * 验证token  * @param token  */ public static String validateToken(String token){  try {   return JWT.require(Algorithm.HMAC512(secret))     .build()     .verify(token.replace(tokenPrefix, ""))     .getSubject();  } catch (TokenExpiredException e){   throw new ApiException(ResultInfo.unauthorized("token已经过期"));  } catch (Exception e){   throw new ApiException(ResultInfo.unauthorized("token验证失败"));  } } /**  * 检查token是否需要更新  * @param token  * @return  */ public static boolean isNeedUpdate(String token){  //获取token过期时间  Date expiresAt = null;  try {   expiresAt = JWT.require(Algorithm.HMAC512(secret))     .build()     .verify(token.replace(tokenPrefix, ""))     .getExpiresAt();  } catch (TokenExpiredException e){   return true;  } catch (Exception e){   throw new ApiException(ResultInfo.unauthorized("token验证失败"));  }  //如果剩余过期时间少于过期时常的一般时 需要更新  return (expiresAt.getTime()-System.currentTimeMillis()) < (expireTime>>1); }}

yaml属性配置

jwt: header: "Authorization" #token返回头部 tokenPrefix: "Bearer " #token前缀 secret: "qwertyuiop7418520" #密钥 expireTime: 1 #token有效时间 (分钟) 建议一小时以上

登录方法将用户信息存入token中返回

 @Override public Map<String,Object> login(User user) {  //phone是除id外的唯一标志 需要进行检查  if (user.getPhone() == null || user.getPhone().equals(""))   throw new ApiException("手机号不合法");  User selectUser = userDao.selectUserByPhone(user.getPhone());  if (selectUser == null) {   //注册用户   int count = userDao.insertUser(user);   if (count < 1) throw new ApiException(ResultInfo.serviceUnavailable("注册异常"));  }  //将userId存入token中  String token = JWTUtils.createToken(selectUser.getUserId().toString());  Map<String,Object> map = new HashMap<>();  map.put("user",selectUser);  map.put("token",token);  return map; }

注意将token保存到Http 的 header

 @GetMapping("/login") public ResultInfo login(User user, HttpServletResponse response) {  Map<String, Object> map = userService.login(user);  //将token存入Http的header中  response.setHeader(JWTUtils.USER_LOGIN_TOKEN, (String) map.get("token"));  return ResultInfo.success((User)map.get("user")); }

拦截器验证每次请求的token

/** * @Author: xiang * @Date: 2021/5/7 20:56 * <p> * 拦截器:验证用户是否登录 */public class UserLoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {  //http的header中获得token  String token = request.getHeader(JWTUtils.USER_LOGIN_TOKEN);  //token不存在  if (token == null || token.equals("")) throw new ApiException("请先登录");  //验证token  String sub = JWTUtils.validateToken(token);  if (sub == null || sub.equals(""))   throw new ApiException(ResultInfo.unauthorized("token验证失败"));  //更新token有效时间 (如果需要更新其实就是产生一个新的token)  if (JWTUtils.isNeedUpdate(token)){   String newToken = JWTUtils.createToken(sub);   response.setHeader(JWTUtils.USER_LOGIN_TOKEN,newToken);  }  return true; }}
@Configuration@ComponentScan(basePackages = "com.neuq.common") //全局异常处理类需要被扫描才能public class WebMvcConfig implements WebMvcConfigurer { /**  * 注册自定义拦截器  *  * @param registry  */ @Override public void addInterceptors(InterceptorRegistry registry) {  registry.addInterceptor(new UserLoginInterceptor())    .addPathPatterns("/user/**")    .addPathPatterns("/userInfo/**")    .excludePathPatterns("/user/login");//开放登录路径 }}

单点登录

将token或者一个唯一标识UUID=UUID.randomUUID().toString()存进Cookie中(别存在Http的header中了),设置路径为整个项目根路径/*; 往往以这个唯一标识为key,用户信息为value缓存在服务器中!!!

最后

对一个 Java 程序员而言,并发编程能否熟练掌握是判断他是不是优秀的重要标准之一。因为并发编程在 Java 语言中最为晦涩的知识点,它涉及内存、CPU、操作系统、编程语言等多方面的基础能力,更加考验一个程序员的内功深厚程度。

特别是当大数据时代的来临,高并发更加成为了家常便饭,在工作中,我们总是绕不开并发编程的任务。比如说,你想写个程序,一边从文件中读取数据,一边还要做实时计算…所以,想成为一名资深的 Java 后端工程师,并发编程是必须要牢牢把握的。那我们到底应该如何深入学习Java并发编程呢?

推荐一篇文章:作为一名双非本科毕业的Java程序员,我该如何在日益严重的内卷化中避免被裁?









原文转载:http://www.shaoqun.com/a/803573.html

跨境电商:https://www.ikjzd.com/

百思买:https://www.ikjzd.com/w/394

photobucket:https://www.ikjzd.com/w/132

马士基集团:https://www.ikjzd.com/w/1296

gem:https://www.ikjzd.com/w/1997


我们都知道JWT是一个JSON信息传输的开放标准,它可以使用密钥对信息进行数字签名,以确保信息是可验证和可信任的。今天我们来深入总结SpringBoot整合JWT前言我们都知道JWT是一个JSON信息传输的开放标准,它可以使用密钥对信息进行数字签名,以确保信息是可验证和可信任的。今天我们来深入总结SpringBoot整合JWT举例登录过程认证流程首先,前端通过Web表单将自己的用户名和密码发送到后
Yeatrade:https://www.ikjzd.com/w/2276
义乌盈和:https://www.ikjzd.com/w/2277
运去哪:https://www.ikjzd.com/w/2278
tiki:https://www.ikjzd.com/w/2053
dojo:https://www.ikjzd.com/w/2052
环球b2b:https://www.ikjzd.com/w/1762
宝贝真紧要被你夹断了 偷听哥哥嫂子的那段不堪事儿:http://lady.shaoqun.com/m/a/274355.html
啊,姨妹,我受不了了 那晚乘老婆出差去了强行上了小姨子:http://www.30bags.com/a/255129.html
30岁的情侣相爱一次,多久比较好?最好不要超过这个数字:http://www.30bags.com/a/383341.html
外贸推广渠道有哪些:https://www.ikjzd.com/articles/145741
速卖通如何去开车:https://www.ikjzd.com/articles/145734
亚马逊有望将在 2022 年超越沃尔玛成为美国最大的零售商:https://www.ikjzd.com/articles/145751


That's the article: 深入总结SpringBoot整合JWT,这应该是全网讲的最通俗易懂的了
Thank you for visiting my blog, hopefully it can be useful for all of you. Don't forget to share this article with your friends so they also know the interesting info, see you in other article posts.

You are now reading the article 深入总结SpringBoot整合JWT,这应该是全网讲的最通俗易懂的了 with link address https://socialnetworkingupdate.blogspot.com/2021/06/springbootjwt.html

More Articles

Post a Comment

Mas Bago Mas luma

Iklan In-Feed (homepage)

#Advertisement