版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lxj673011332/article/details/81808908
为什么需要JWT
在传统的 session 验证中,服务端必须保存 session ID,用于与用户传过来的 cookie 验证。而在一开始保存 session ID 时, 只会保存在一台服务器上,所以只能由一个 server 应答,就算其他服务器有空闲也无法应答,因此也利用不到分布式服务器的优点。
而 JWT 依赖的是在客户端本地保存验证信息,不需要利用服务器保存的信息来验证,所以任意一台服务器都可以应答,服务器的资源也被较好地利用。
spring集成JWT
- 添加JWT依赖
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
- 添加JWT配置
audience:
clientId: 098f6bcd4621d373cade4e832627b4f6
base64Secret: MDk4ZjZiY2Q0NjIxZDM3M2NhZGU0ZTgzMjYyN2I0ZjY=
name: restapiuser
expiresSecond: 172800
- 配置JWT实体类
@Component
@ConfigurationProperties(prefix = "audience")
public class Audience {
private String clientId;
private String base64Secret;
private String name;
private int expiresSecond;
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public String getBase64Secret() {
return base64Secret;
}
public void setBase64Secret(String base64Secret) {
this.base64Secret = base64Secret;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getExpiresSecond() {
return expiresSecond;
}
public void setExpiresSecond(int expiresSecond) {
this.expiresSecond = expiresSecond;
}
}
- 使用拦截器配置JWT
@Component
public class JWTInterceptor implements HandlerInterceptor {
@Autowired
private Audience audience;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
final String authHeader = request.getHeader("authorization");
if ("OPTIONS".equals(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
return true;
} else {
if (null == authHeader || !authHeader.startsWith("bearer;")) {
throw new ServiceRuntimeException(new ErrorDetails(1004));
}
}
final String token = authHeader.substring(7);
try {
final Claims claims = JwtHelper.parseJWT(token, audience.getBase64Secret());
if (claims == null) {
throw new ServiceRuntimeException(new ErrorDetails(1004));
}
request.setAttribute("CLAIMS", claims);
return true;
} catch (final Exception e) {
throw new ServiceRuntimeException(new ErrorDetails(1004));
}
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
}
}
- 配置拦截器
@Configuration
public class WebConfiguration implements WebMvcConfigurer {
@Bean
JWTInterceptor jwtInterceptor(){
return new JWTInterceptor();
}
//spring拦截器加载在springcontentText之前,所以这里用@Bean提前加载。否则会导致过滤器中的@AutoWired注入为空
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(jwtInterceptor()).addPathPatterns("/manage/**")
.excludePathPatterns(Arrays.asList("/", "/login"));
}
}
- 登录返回token
String jwtToken = JwtHelper.createJWT(admin.getAdminUsername(), admin.getAdminId(), audience.getClientId(),
audience.getName(), audience.getExpiresSecond()*1000, audience.getBase64Secret());
jwtToken = "bearer;" + jwtToken;
- jwt工具类
public class JwtHelper {
/**
* 解析jwt
*/
public static Claims parseJWT(String jsonWebToken, String base64Security){
try{
Claims claims = Jwts.parser()
.setSigningKey(DatatypeConverter.parseBase64Binary(base64Security))
.parseClaimsJws(jsonWebToken).getBody();
return claims;
}catch (Exception e){
return null;
}
}
/**
*
* @param name
* @param userId
* @param audience
* @param issuer
* @param TTLMillis
* @param base64Security
* @return
*/
public static String createJWT(String name, Integer userId,
String audience, String issuer, long TTLMillis, String base64Security){
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
//生成签名密钥
byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(base64Security);
Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
//添加构成JWT的参数
JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT")
.claim("unique_name", name)
.claim("userid", userId)
.setIssuer(issuer)
.setAudience(audience)
.signWith(signatureAlgorithm, signingKey);
//添加Token过期时间
if (TTLMillis >= 0) {
long expMillis = nowMillis + TTLMillis;
Date exp = new Date(expMillis);
builder.setExpiration(exp).setNotBefore(now);
}
//生成JWT
return builder.compact();
}
}