Spring Boot 整合 JWT JSON Web Token
Spring Boot JWT About 5,002 words添加依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.19.1</version>
</dependency>
获取 Token
@RestController
public class LoginController {
@GetMapping("/login")
public TokenDto login() {
try {
Algorithm algorithm = Algorithm.HMAC256("secret");
String token = JWT.create()
.withIssuer("auth0")
// 自定义 payload 键值
.withClaim("testKey", "testValue")
.withExpiresAt(Date.from(LocalDateTime.now().plusDays(3).toInstant(ZoneOffset.UTC)))
.sign(algorithm);
return TokenDto.builder().accessToken(token).build();
} catch (JWTCreationException exception) {
//Invalid Signing configuration / Couldn't convert Claims.
}
return null;
}
}
请求资源
curl \
"http://localhost:8080/login"
返回
{
"accessToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJhdXRoMCIsInRlc3RLZXkiOiJ0ZXN0VmFsdWUiLCJleHAiOjE2NTE2NjQxMzh9.EW5XMP5Z1YY_3XFEmojUcUh601i-OuBwgMBkRh453Q8"
}
Base64 解密
header
{
"typ": "JWT",
"alg": "HS256"
}
payload
{
"iss": "auth0",
"testKey": "testValue",
"exp": 1651664138
}
signature
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
"secret"
)
请求资源
拦截器,异常返回401
。
@Slf4j
@Component
public class TokenFilter implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
try {
String authorization = request.getHeader("Authorization");
String token = authorization.split(" ")[1];
Algorithm algorithm = Algorithm.HMAC256("secret");
JWTVerifier verifier = JWT.require(algorithm)
.withIssuer("auth0")
.build(); //Reusable verifier instance
DecodedJWT jwt = verifier.verify(token);
log.info("header#{}, payload#{}, sign#{}, jwt#{}", jwt.getHeader(), jwt.getPayload(), jwt.getSignature(), jwt);
} catch (Exception exception){
//Invalid signature/claims
log.error("exception#{}", exception.getMessage(), exception);
response.setStatus(HttpStatus.UNAUTHORIZED.value());
return false;
}
return true;
}
}
拦截器配置
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Resource
private TokenFilter tokenFilter;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(tokenFilter).addPathPatterns("/**")
.excludePathPatterns("/login");
}
}
模拟资源接口
@RestController
public class ResourceController {
@GetMapping("/resource")
public String resource() {
return "resource";
}
}
请求资源
curl \
-H "Authorization: bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJhdXRoMCIsInRlc3RLZXkiOiJ0ZXN0VmFsdWUiLCJleHAiOjE2NTE2NjQxMzh9.EW5XMP5Z1YY_3XFEmojUcUh601i-OuBwgMBkRh453Q8" \
"http://localhost:8080/resource"
解码 API
String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJhdXRoMCIsInRlc3RLZXkiOiJ0ZXN0VmFsdWUiLCJleHAiOjE2NTE2NjQxMzh9.EW5XMP5Z1YY_3XFEmojUcUh601i-OuBwgMBkRh453Q8";
try {
DecodedJWT jwt = JWT.decode(token);
System.out.println("Header#" + jwt.getHeader());
System.out.println("Payload#" + jwt.getPayload());
System.out.println("Signature#" + jwt.getSignature());
System.out.println("Token#" + jwt.getToken());
System.out.println("Type#" + jwt.getType());
System.out.println("Algorithm#" + jwt.getAlgorithm());
System.out.println("Issuer#" + jwt.getIssuer());
System.out.println("Claims#" + jwt.getClaims());
System.out.println("ExpiresAt#" + jwt.getExpiresAt());
System.out.println("Id#" + jwt.getId());
System.out.println("KeyId#" + jwt.getKeyId());
System.out.println("Subject#" + jwt.getSubject());
System.out.println("Audience#" + jwt.getAudience());
System.out.println("ContentType#" + jwt.getContentType());
} catch (JWTDecodeException exception){
//Invalid token
}
输出
Header#eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
Payload#eyJpc3MiOiJhdXRoMCIsInRlc3RLZXkiOiJ0ZXN0VmFsdWUiLCJleHAiOjE2NTE2NjQxMzh9
Signature#EW5XMP5Z1YY_3XFEmojUcUh601i-OuBwgMBkRh453Q8
Token#eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJhdXRoMCIsInRlc3RLZXkiOiJ0ZXN0VmFsdWUiLCJleHAiOjE2NTE2NjQxMzh9.EW5XMP5Z1YY_3XFEmojUcUh601i-OuBwgMBkRh453Q8
Type#JWT
Algorithm#HS256
Issuer#auth0
Claims#{iss="auth0", testKey="testValue", exp=1651664138}
ExpiresAt#Wed May 04 19:35:38 CST 2022
Id#null
KeyId#null
Subject#null
Audience#null
ContentType#null
JWT 缺点
无法满足如下场景
- 退出登录(
Token
泄露,有效期内Token
仍然有效) - 修改密码(
Token
泄露,修改密码后Token
仍然有效) Token
续签(需通过refresh token
再次刷新)
Token 续签流程
- 前端请求资源,服务端校验
access_token
过期,返回401
。 - 前端携带
refresh_token
请求刷新Token
,服务端校验refresh_token
,并返回新Token
。 - 前端使用最新
Token
请求资源。
官网
Views: 1,378 · Posted: 2022-09-30
————        END        ————
Give me a Star, Thanks:)
https://github.com/fendoudebb/LiteNote扫描下方二维码关注公众号和小程序↓↓↓
Loading...