引入JWT依赖
<jwt.version>0.9.1</jwt.version>
<!-- JWT相关 -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jwt.version}</version>
</dependency
<!-- JWT相关 -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
聚合工程和common
各引入一份JWT依赖
编写生成/解析token工具类
@Slf4j
public class JWTUtil {
/** token 过期时间,7天 */
private static final long EXPIRE = 1000 * 60 * 60 * 24 * 7;
/** 加密秘钥 */
private static final String SERCET = "xdclass";
/** 令牌前缀 */
private static final String TOKEN_PREFIX = "ovo";
/** subject */
private static final String SUBJECT = "xdclass";
/** 生成Token */
public static String geneJsonWebToken(LoginUser loginUser) {
if(loginUser == null){
throw new NullPointerException(" loginUser 对象为空");
}
String token = Jwts.builder().setSubject(SUBJECT)
.claim("id", loginUser.getId())
.claim("name", loginUser.getName())
.claim("mail", loginUser.getMail())
.claim("avater", loginUser.getAvater())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
.signWith(SignatureAlgorithm.HS256, SERCET).compact();
return TOKEN_PREFIX + token;
}
/** 校验token */
public static Claims checkJWT(String token) {
try {
return Jwts.parser()
.setSigningKey(SERCET)
.parseClaimsJws(token.replace(TOKEN_PREFIX, "")).getBody();
} catch (Exception e) {
log.info("token 解析失败");
return null;
}
}
}
生成token时将登录用户的部分信息放入token中进行加密,
后续进行操作时可以解析token取出登录用户的信息存入线程中
在登录方法中生成token并返回
@Override
public JsonData login(UserLoginRequest loginRequest) {
UserDO user = lambdaQuery().eq(UserDO::getMail, loginRequest.getMail()).one();
if(user == null){
return JsonData.buildResult(BizCodeEnum.ACCOUNT_UNREGISTER);
}
String pwd = SecureUtil.sha256(loginRequest.getPwd() + user.getSecret());
if(!pwd.equals(user.getPwd())){
return JsonData.buildResult(BizCodeEnum.ACCOUNT_PWD_ERROR);
}
// 登录成功,生成token, TODO 保存到redis
LoginUser loginUser = BeanUtil.copyProperties(user, LoginUser.class);
String token = JWTUtil.geneJsonWebToken(loginUser);
return JsonData.buildSuccess(token, "登录成功");
}
配置登录拦截器
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 取出 token
String accessToken = request.getHeader("token");
if (accessToken == null){
accessToken = request.getParameter("token");
}
// token 为 null
if(StrUtil.isBlank(accessToken)){
CommonUtil.sendJsonMessage(response, JsonData.buildResult(BizCodeEnum.ACCOUNT_UNLOGIN));
}
// 解析 token
Claims claims = JWTUtil.checkJWT(accessToken);
if(claims == null){
CommonUtil.sendJsonMessage(response, JsonData.buildResult(BizCodeEnum.ACCOUNT_UNLOGIN));
return false;
}
// 取出解析token后的信息
Long userId = Long.valueOf(claims.get("id").toString());
String name = (String) claims.get("name");
String mail = (String) claims.get("mail");
String avater = (String) claims.get("avater");
// 封装成 LoginUser 对象
LoginUser loginUser = LoginUser.builder()
.id(userId)
.name(name)
.mail(mail)
.avater(avater)
.build();
// 将 loginUser 放入上下文
BaseContext.setCurrentId(userId);
BaseContext.setLoginUser(loginUser);
return true;
}
}
拦截请求, 解析token, 将解析后的用户信息存入线程中, 方便后面使用
配置登录拦截器的拦截路径
@Slf4j
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry){
registry.addInterceptor(new LoginInterceptor())
// 拦截的路径
.addPathPatterns("/api/user/*/**","/api/address/*/**")
// 不拦截的路径
.excludePathPatterns("/api/user/*/send_code","/api/user/*/captcha",
"/api/user/*/login","/api/user/*/register","/api/user/*/upload");
}
}
请求上下文类
public class BaseContext {
/**
* 用于将当前线程的 ID 设置为指定的 id 值。
* 它将 id 值存储在当前线程的 threadLocal 对象中,以便在其他地方可以获取到当前线程的 ID。
*/
public static ThreadLocal<Long> threadID = new ThreadLocal<>();
public static void setCurrentId(Long id) {
threadID.set(id);
}
public static Long getCurrentId() {
return threadID.get();
}
public static void removeCurrentId() {
threadID.remove();
}
/**
* 用于将当前线程的用户名设置为指定的 LoginUser 值。
* 它将 LoginUser 值存储在当前线程的 threadLoginUser 对象中,以便在其他地方可以获取到当前线程的登录信息。
*/
public static ThreadLocal<LoginUser> threadLoginUser = new ThreadLocal<>();
public static void setLoginUser(LoginUser loginUser) {
threadLoginUser.set(loginUser);
}
public static LoginUser getLoginUser() {
return threadLoginUser.get();
}
}