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加密,構(gòu)成第一部分:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
2.載荷-payload
載荷就是存放有效信息的地方,包含三個部分
標準中注冊的聲明
公共的聲明
私有的聲明
這其中標準中注冊的聲明(建議但不強制使用)包括如下部分
iss : jwt簽發(fā)者
sub: jwt面向的用戶
aud: 接收方
exp: jwt過期時間
nbf: 定義在什么時間之前,jwt都是不可用的
iat: jwt簽發(fā)時間
jwt唯一身份標識
公共聲明存放用戶或業(yè)務(wù)等相關(guān)信息
私有聲明是提供者和消費者所共同定義的聲明,一般不建議存放敏感信息,因為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);
//創(chuàng)建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);
}
/**
* 根據(jù)token獲取載荷信息
* @param token
* @return
*/
public static Map<String, Claim> getPayloadByToken(String token) {
return verify(token).getClaims();
}
2.3 創(chuàng)建攔截器
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轉(zhuǎn)為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();
}
}
古今成大事者,不唯有超世之才,必有堅韌不拔之志!

浙公網(wǎng)安備 33010602011771號