- 在配置文件pom.xml中添加jwt生成依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.4.0</version>
</dependency>
- 在utils包下创建一个jwtUtil的工具类实现token的统一颁发及校验
package org.example.utils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import java.util.Date;
import java.util.Map;
public class JwtUtil {
private static final String KEY = "xuanmao";//设置密钥(要想非对称加密这里换成私钥)
//接收业务数据,生成token并返回
public static String genToken(Map<String, Object> claims) {
return JWT.create()
.withClaim("claims", claims)//token中加入用户信息
.withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 12))//设置超时时间
.sign(Algorithm.HMAC256(KEY));//设置加密类型及密钥
}
//接收token,验证token,并返回业务数据
public static Map<String, Object> parseToken(String token) {
//去除token的前缀标记"Bearer "
var newToken = token.contains("Bearer ")?token.substring("Bearer ".length()):token;
return JWT.require(Algorithm.HMAC256(KEY))//要想非对称加密这里换成公钥
.build()
.verify(newToken)
.getClaim("claims")
.asMap();
}
}
- 在utils包下创建ThreadLocalUtil工具类用于将用户信息存放在ThreadLocal中,方便在方法中获取token中的信息
package org.example.utils;
import java.util.HashMap;
import java.util.Map;
/**
* ThreadLocal 工具类
*/
@SuppressWarnings("all")
public class ThreadLocalUtil {
//提供ThreadLocal对象,
private static final ThreadLocal THREAD_LOCAL = new ThreadLocal();
//根据键获取值
public static <T> T get(){
return (T) THREAD_LOCAL.get();
}
//存储键值对
public static void set(Object value){
THREAD_LOCAL.set(value);
}
//清除ThreadLocal 防止内存泄漏
public static void remove(){
THREAD_LOCAL.remove();
}
}
- 在intercopters包创建拦截器实现接口响应前的身份校验
package org.example.intercopters;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.example.utils.JwtUtil;
import org.example.utils.ThreadLocalUtil;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import java.util.Map;
@Component //注册拦截器 将其放入ioc容器中
public class LoginInterceptor implements HandlerInterceptor {
//创建登录身份校验拦截器
@Override //请求开始前触发的拦截方法
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//令牌验证
String token = request.getHeader("Authorization");
try {
Map<String, Object> claims = JwtUtil.parseToken(token);
//把用户信息存储到ThreadLocal中,tomcat会在每次接口请求时创建一个线程
//而ThreadLocal中存储的数据是线程安全的
ThreadLocalUtil.set(claims);
//放行
return true;
} catch (Exception e) {
//设置响应状态码
response.setStatus(401);
//设置响应字符集和响应内容
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html; charset=UTF-8");
String errorMessage = "未登录";
response.getWriter().write("{\"error\": \"" + errorMessage + "\"}");
//不放行
return false;
}
}
@Override //请求完成后触发的拦截方法
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//清空ThreadLocal中的数据防止内存泄漏
ThreadLocalUtil.remove();
}
}
- 在config包下创建配置类并在配置类中使用拦截器
package org.example.config;
import org.example.intercopters.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration //把配置类添加到ioc容器中
public class WebConfig implements WebMvcConfigurer {
@Autowired //注入ioc容器中的LoginIntercopter拦截器
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//登录和注册接口不拦截
registry.addInterceptor(loginInterceptor).excludePathPatterns("/user/login", "/user/register");
}
}