该工具类用于生成token和解析token对象
代码
package com.gdpu.util;
import com.gdpu.exception.TokenException;
import com.gdpu.bo.UserTokenBO;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import java.security.Key;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
/**
* @author mojiazhu
* @date 2022/12/10 8:26
* <p>
* token工具类 鉴权token JWT由三部分构成{header(base64后的),payload(base64后的),secret组成}
*/
@Slf4j
public class TokenUtil {
//设置本次请求的threadLocal
private static final ThreadLocal<UserTokenBO> threadLocal = new ThreadLocal<>();
//token属性名
public static final String USER_TOKEN = "Token";
//加密算法
public static final Key KEY = Keys.secretKeyFor(SignatureAlgorithm.HS512);
//过期时间1小时-7天
private static final Long EXPIRATION = 3600L;
private static final Long EXPIRATION_REMEMBER = 604800L;
/**
* 生成JwtToken
*
* @param userTokenBO 用户信息
* @return JwtToken
*/
public static String createJwtToken(UserTokenBO userTokenBO, boolean isRememberMe) {
try {
Long expiration = isRememberMe ? EXPIRATION_REMEMBER : EXPIRATION;
Map<String, Object> map = new LinkedHashMap<>(5);
map.put("userId", userTokenBO.getUserId());
map.put("objectId", userTokenBO.getObjectId());
map.put("userType", userTokenBO.getUserType());
log.info("[用户登录]保存用户信息string的字段为:{}", map);
return Jwts.builder()
.setClaims(map)
.setExpiration(new Date(System.currentTimeMillis() + expiration * 1000))
.signWith(KEY)
.compact();
} catch (Exception e) {
log.error("[用户登录]生成jwt_token失败,账号为:{}", userTokenBO.getUserId());
return null;
}
}
/**
* 验证token是否有效,并返回token的payload
*
* @param token
* @return
*/
public static boolean verifyJwtToken(String token) {
try {
//获取token中的claims对象,获取失败抛出异常
Claims claims = Jwts.parserBuilder().setSigningKey(KEY).build().parseClaimsJws(token).getBody();
//将claims转换为UserTokenBO对象
UserTokenBO userTokenBO = new UserTokenBO();
userTokenBO.setUserId(claims.get("userId", Double.class).intValue());
userTokenBO.setObjectId(claims.get("objectId", Double.class).intValue());
userTokenBO.setUserType(claims.get("userType", Double.class).intValue());
//将用户信息存在ThreadLocal中
setUserDetail(userTokenBO);
return true;
} catch (Exception e) {
throw new TokenException("Token验证失败");
}
}
/**
* 将token解析出来的用户信息自动存在ThreadLocal中
*
* @param userTokenBO
*/
private static void setUserDetail(UserTokenBO userTokenBO) {
threadLocal.set(userTokenBO);
}
/**
* 获取值
*
* @return
*/
public static UserTokenBO getUserDetail() {
return threadLocal.get();
}
}
自定义的token异常
package com.gdpu.exception;
import lombok.extern.slf4j.Slf4j;
/**
* @author mojiazhu
* @date 2022/12/10 21:08
*/
@Slf4j
public class TokenException extends RuntimeException {
public TokenException(String message) {
super(message);
}
}
token拦截器
package com.gdpu.interceptor;
import com.gdpu.util.TokenUtil;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
* @author mojiazhu
* @date 2022/12/10 22:47
*/
@Slf4j
@Component
public class TokenInterceptor implements HandlerInterceptor {
//路径匹配器,支持通配符
public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
//忽略拦截的URL
private String urls[] = {
"/v2/**"
};
/**
* 进入controller前拦截请求 token验证通过返回true
*
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String requestURI = request.getRequestURI();
String token = request.getHeader(TokenUtil.USER_TOKEN);
String method = request.getMethod();
if (!"OPTIONS".equals(method)) {
//遍历需要拦截的路径
for (String item : this.urls) {
boolean match = PATH_MATCHER.match(item, requestURI);
if (match) {
// log.info("本次请求不需要拦截,请求地址为:{}", requestURI);
return true;
}
}
}
//检验token
return TokenUtil.verifyJwtToken(token);
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable Exception ex) throws Exception {
}
}
配置token拦截器
package com.gdpu.config;
import com.gdpu.interceptor.TokenInterceptor;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author mojiazhu
* @date 2022/12/11 1:02
*/
@Configuration
@AllArgsConstructor
public class WebMvcConfig implements WebMvcConfigurer {
private final TokenInterceptor tokenInterceptor;
/**
* 注册token拦截器
*
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(tokenInterceptor).addPathPatterns("/**");
}
}
依赖
<jjwt.version>0.11.2</jjwt.version>
<!-- jjwt,token鉴权 -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>${jjwt.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>${jjwt.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-gson</artifactId>
<version>${jjwt.version}</version>
<scope>runtime</scope>
</dependency>