JWT令牌
- 前言
- 一、JWT是什么?
- 二、JWT与传统Cookie+Session的对比
- 三、JWT
- 1. JWT的功能
- 2. JWT的结构
- 3. JWT的使用
前言
主要介绍了SpringBoot集成JWT令牌详细说明,JWT方式校验方式更加简单便捷化,无需通过redis缓存,而是直接根据token取出保存的用户信息,以及对token可用性校验,单点登录,验证token更为简单。
一、JWT是什么?
JWT简称JSON、Web、Token,也就是通过JSON形式作为web与应用中的令牌,用于在各方之间安全地将信息作为JSON对象传输。在数据传输过程中还可以完成数据加密、签名等相关处理。
JSON、Web、Token是一个开放标准,它定义了一种紧凑的、自包含的方式,用于在各方之间以JSON对象安全的传输信息。此信息可以验证和信任,因为它是数字签名的,JWT可以使用秘密或使用RSA或ECDSA的公钥/私钥对进行签名。
官网:http://jwt.io/introduction/
二、JWT与传统Cookie+Session的对比
- 在传统的用户登录认证中,因为http是无状态的,所以都是采用session方式。用户登录成功,服务端会保证一个session,当然会给客户端一个sessionId,客户端会把sessionId保存在cookie中,每次请求都会携带这个sessionId。
传统Cookie+ Session认证
-
cookie+session这种模式通常是保存在内存中,而且服务从单服务到多服务会面临的session共享问题,随着用户量的增多,开销就会越大。而JWT不是这样的,只需要服务端生成token,客户端保存这个token,每次请求携带这个token,服务端认证解析就可。
-
JWT方式校验方式更加简单便捷化,无需通过redis缓存,而是直接根据token取出保存的用户信息,以及对token可用性校验,单点登录,验证token更为简单。
JWT 认证
用户进行认证,向服务器发送请求,服务器响应请求并进行认证,认证通过后生成JWT即token,响应给前端;后面的每次请求都携带JWT,服务器拦截请求验证token的有效性,正确的token执行业务逻辑响应数据,错误的token返回错误信息给前端,前端展示相应的的信息。
三、JWT
1. JWT的功能
JWT主要的功能有授权
、信息交互
两种
授权: 用户的授权,一旦用户登录后获得了token,后续一些需要用户权限的请求就不会拒绝请求。
信息交互: JSON Web Token是在各方之间安全传输信息的好方法。因为可以对JWT进行签名(例如:使用公钥/私钥对),所以可以确保发送方信息,由于签名是使用标头和有效负载计算的,因此可以验证内容是否遭到篡改,保证信息的完整性。
2. JWT的结构
本质是一个字符串,token ====> header.payload.singnature
令牌的组成: 标头(header) 、有效负荷(payload) 、签名(singnature)
JWT通常所示:xxxxxx.yyyyyy.zzzzzz
- header: 标头通常由两部分组成即令牌的类型(JWT)和使用的算法类型。【通常使用Base64编码组成JWT结构的第一部分】
{"alg":"HS256","typ":"JWT"
}
- payload: 有效负载,存储用户的相关的信息和其他数据的声明。【通常使用Base64编码组成JWT结构的第二部分】
{"username":"qiumin","password":"123456"
}
- singnature: 签名,与前面两个部分生成JWT,该签名不能让其他人知道,是保证token不被串改,保证信息的安全。【通常使用Base64编码组成JWT结构的第二部分】
header+"."+payload+"."+singnature ---> 组成唯一的token
3. JWT的使用
- 导入JWT依赖
<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.10.3</version>
</dependency>
- 生成token
@Testpublic void contentLoad(){HashMap<String,Object> map = new HashMap<>();Calendar instance = Calendar.getInstance();instance.add(Calendar.SECOND,180);String token = JWT.create().withHeader(map) //header.withClaim("username", "qiumin") //payload.withClaim("password", "123456") //payload.withExpiresAt(instance.getTime()).sign(Algorithm.HMAC256("!FhSD!#VDZF%#FDBD"));//签名System.out.println(token);}
- 验证解析token
@Testpublic void Auth(){JWTVerifier verifier = JWT.require(Algorithm.HMAC256("!FhSD!#VDZF%#FDBD")).build();DecodedJWT verify = verifier.verify("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwYXNzd29yZCI6IjEyMzQ1NiIsImV4cCI6MTY1NzQzODUxNSwidXNlcm5hbWUiOiJxaXVtaW4ifQ.1TIUuWP1d1-vHc71oTw2pH5LAxtCehiiRnaK3tIZob8");System.out.println(verify.getHeader());System.out.println("payload: "+verify.getClaim("username").asString());System.out.println("payload: "+verify.getClaim("password").asString());System.out.println("过期时间: "+verify.getExpiresAt());}
- 常见的JWT异常,封装成工具类JwtUtils
SignatureVerificationException: 无效签名。
TokenExpiredException: token过期。
AlgorithmMismatchException: token算法不一致。
InvalidClaimException: 失效payload异常。
package com.qiumin.utils;import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;import java.util.Calendar;
import java.util.Map;/*** @author qiumin* @classname JWTUtils* @Description love code* @date 2022-07-10 15:33*/public class JwtUtils {private static final String SING = "!FhSD!#VhDZF%#FDBD";/*** 获得Token* @param map1 header* @param map2 payload* */public static String getToken(Map<String,Object> map1, Map<String,String> map2){Calendar instance = Calendar.getInstance();instance.add(Calendar.SECOND,180); //过期时间JWTCreator.Builder builder = JWT.create();builder.withHeader(map1); //headermap2.forEach((k,v)->{builder.withClaim(k,v);}); //payloadbuilder.withExpiresAt(instance.getTime()); //过期时间String token = builder.sign(Algorithm.HMAC256(SING));//签名return token;}/*** 验证token* @param token 令牌* */public static void verify(String token){JWTVerifier build = JWT.require(Algorithm.HMAC256(SING)).build();build.verify(token);}/*** 获取token中的信息* @param token 令牌* */public static DecodedJWT analysis(String token){return JWT.require(Algorithm.HMAC256(SING)).build().verify(token);}}
- 拦截器配置验证token
创建拦截器的类,配置WebMvcConfigurer,将自己的自定义拦截器装配到容器中
package com.qiumin.interceptor;import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qiumin.utils.JwtUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;/*** JwtInterceptor拦截器类** @author qiumin* @classname JwtInterceptor* @Description love code* @date 2022-07-14 13:14*/public class JwtInterceptor implements HandlerInterceptor {/*** 拦截器* @param request* @param response* @param handler* @return* @throws Exception*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String token = request.getHeader("token");HashMap<String, Object> map = new HashMap<>();JwtUtils jwtUtils = new JwtUtils();try {jwtUtils.verify(token);return true;}catch (SignatureVerificationException e){e.printStackTrace();map.put("msg","无效签名!");}catch (TokenExpiredException e){e.printStackTrace();map.put("msg","token过期!");}catch (AlgorithmMismatchException e){e.printStackTrace();map.put("msg","token算法不一致!");}catch (Exception e){e.printStackTrace();map.put("msg","token无效!");}map.put("state",false);response.setContentType("application/json;charset=UTF-8");//响应给前端response.getWriter().println(new ObjectMapper().writeValueAsString(map));return false;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {HandlerInterceptor.super.afterCompletion(request, response, handler, ex);}
}
配置拦截器
package com.qiumin.config;import com.qiumin.interceptor.JwtInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/*** @author qiumin* @classname InterceptorConfig* @Description love code* @date 2022-07-14 13:37*/@Configuration
public class InterceptorConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new JwtInterceptor()).addPathPatterns("/user/test2") //拦截的路径请求.excludePathPatterns("/user/login"); //放行的请求路径}
}
参考文章:https://blog.csdn.net/m0_57752520/article/details/125785908
如有问题可联系博主