SpringBoot集成JWT
一、JWT的简述
JWT 是Json Web Token的简称;JWT由头部(header)、载荷(payload)、签证(signature)三部分组成;其三部分之间用.分隔,例如:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6IjEiLCJleHAiOjE2NTkxMDU0MTIsInVzZXJuYW1lIjoiemhhbmdzYW4ifQ.ciurjE4dS3CBckl25Df6eaQvzJIuiM5Wk-LD_gfoEBs
1. 头部-header
jwt的头部承载两部分信息
- 声明类型,这里时jwt
- 声明加密的算法,通常直接使用 HMAC SHA256
如:
{
'typ': 'JWT',
'alg': 'HS256'
}
使用base64加密,构成第一部分:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
2.载荷-payload
载荷就是存放有效信息的地方,包含三个部分
标准中注册的声明
公共的声明
私有的声明
这其中标准中注册的声明(建议但不强制使用)包括如下部分
iss : jwt签发者
sub: jwt面向的用户
aud: 接收方
exp: jwt过期时间
nbf: 定义在什么时间之前,jwt都是不可用的
iat: jwt签发时间
jwt唯一身份标识
公共声明存放用户或业务等相关信息
私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息
如:
{
"sub": "18700000000",
"name": "songweipeng",
"admin": true
}
BASE64 加密
eyJpZCI6IjEiLCJleHAiOjE2NTkxMDU0MTIsInVzZXJuYW1lIjoiemhhbmdzYW4ifQ var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload); var signature = HMACSHA256(encodedString, '密钥');
加密之后,得到signature签名信息。
ciurjE4dS3CBckl25Df6eaQvzJIuiM5Wk-LD_gfoEBs
3.签证-signature
jwt的第三部分是一个签证信息,这个签证信息由三部分组成
二、SpringBoot 集成
2.1 jwt依赖
<!-- jwt依赖 --> <!-- https://mvnrepository.com/artifact/com.auth0/java-jwt --> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.18.2</version> </dependency>
2.2 获取token的工具类
import com.auth0.jwt.JWT; import com.auth0.jwt.JWTCreator; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.interfaces.DecodedJWT; import java.util.Calendar; import java.util.Map; /** * @Project: * @Description: * @Auther: songwp * @Date: 2022/7/22 22:23 **/ public class JWTUtils { private static final String SING = "@#%$^&lu123456"; /** * 生成token */ public static String getToken(Map<String,String> map){ Calendar instance = Calendar.getInstance(); //默认7天过期 instance.add(Calendar.DATE,7); //创建jwt builder JWTCreator.Builder builder = JWT.create(); map.forEach((k,v)->{ builder.withClaim(k,v); }); String token = builder.withExpiresAt(instance.getTime()) .sign(Algorithm.HMAC256(SING)); return token; } /** * 验证token合法性 */ public static DecodedJWT verify(String token){ return JWT.require(Algorithm.HMAC256(SING)).build().verify(token); } /** * 根据token获取载荷信息 * @param token * @return */ public static Map<String, Claim> getPayloadByToken(String token) { return verify(token).getClaims(); }
2.3 创建拦截器
import com.auth0.jwt.exceptions.AlgorithmMismatchException; import com.auth0.jwt.exceptions.SignatureVerificationException; import com.auth0.jwt.exceptions.TokenExpiredException; import com.auth0.jwt.interfaces.DecodedJWT; import com.fasterxml.jackson.databind.ObjectMapper; import com.songwp.hutooldemo.untils.JWTUtils; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.HashMap; import java.util.Map; /** * @Project: * @Description: * @Auther: songwp * @Date: 2022/7/22 22:31 **/ public class JWTInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("Authorization");
Result<T> result = new Result<T>();
try {
//验证令牌
DecodedJWT verify = JwtUtils.verify(token);
UserTokenInfoHolder.setUserTokenInfo(verify.getClaims());
return true;
} catch (SignatureVerificationException e) {
e.printStackTrace();
result.setCode(-1);
result.setMessage("无效签名");
} catch (TokenExpiredException e) {
e.printStackTrace();
result.setCode(-1);
result.setMessage("token过期");
} catch (AlgorithmMismatchException e) {
e.printStackTrace();
result.setCode(-1);
result.setMessage("token算法不一致");
} catch (JWTDecodeException e) {
e.printStackTrace();
result.setCode(-1);
result.setMessage("token不合法");
} catch (NullPointerException e) {
e.printStackTrace();
result.setCode(-1);
result.setMessage("token不能为空");
} catch (Exception e) {
e.printStackTrace();
result.setCode(-1);
result.setMessage("token无效");
}
//将返回值result转为json
String json = new ObjectMapper().writeValueAsString(result);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().println(json);
return false;
}
}
2.4 拦截器注册
/**
* @Project:
* @Description:
* @Auther: songwp
* @Date: 2022/7/22 22:33
**/
import com.songwp.hutooldemo.interceptor.JWTInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 注册拦截器
*/
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
/**
* 配置跨域访问
* @param registry
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")//项目中的所有接口都支持跨域
.allowedOrigins("*")//所有地址都可以访问,也可以配置具体地址
.allowCredentials(true)
.allowedMethods("*")//"GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS"
.maxAge(3600);// 跨域允许时间
}
/**
* 注册拦截器
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new JWTInterceptor())
//拦截
.addPathPatterns("/user/test")
//放行
.excludePathPatterns("/user/login");
}
@Bean
public JWTInterceptor tokenInterceptor(){
return new JWTInterceptor();
}
}
古今成大事者,不唯有超世之才,必有坚韧不拔之志!