会话跟踪方案
JWT令牌
JWT依赖
<!-jwt依赖-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.19.2</version>
</dependency>
JWT工具类
public class JwtUtil {
private static final String KEY = "itheima";
//接收业务数据,生成token并返回
public static String genToken(Map<String, Object> claims) {
return JWT.create()
.withClaim("claims", claims)//设置我们给定的数据
.withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 12))//令牌的有效期
.sign(Algorithm.HMAC256(KEY));//设置签名算法和密钥
}
//接收token,验证token,并返回业务数据
public static Map<String, Object> parseToken(String token) {
return JWT.require(Algorithm.HMAC256(KEY))//设置解析的算法和密钥
.build()
.verify(token)//对给定的token进行验证
.getClaim("claims")//获取名为claims的声明
.asMap();//转换为一个map数据结构
}
}
拦截器
访问路径先经过配置拦截器
如果没有拦截到直接访问控制层
如果拦截到,则进入定义的拦截器,在preHandle中进行逻辑处理。
返回true,则放行,访问控制层,返回false,不放行,无权访问
执行流程
定义拦截器
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//令牌验证
String token = request.getHeader("Authorization");
//验证token
try {
Map<String, Object> claims = JwtUtil.parseToken(token);//解析不出错即正确,解析异常即错误
String role = (String) claims.get("role");
if(role.equals("admin")){
String requestURI = request.getRequestURI();
if(requestURI.contains("/staff")){
return false;
}
//把业务数据存储到ThreadLocal中
ThreadLocalUtil.set(claims);
return true;
} else if (role.equals("staff")) {
String requestURI = request.getRequestURI();
if(requestURI.contains("/admin")){
return false;
}
//把业务数据存储到ThreadLocal中
ThreadLocalUtil.set(claims);
return true;
}
//把业务数据存储到ThreadLocal中
// ThreadLocalUtil.set(claims);
//放行
return false;
} catch (Exception e) {
//http响应状态码为401
response.setStatus(401);
//不放行
return false;
}
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//清空ThreadLocal中的数据
ThreadLocalUtil.remove();
}
}
配置拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//登录接口和注册接口不拦截
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/login");
}
}
全局异常处理
未处理
处理流程
代码实现
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class) //接收所有异常
public Result handleException(Exception e){
e.printStackTrace();
return Result.error(StringUtils.hasLength(e.getMessage())?e.getMessage():"操作失败");
}
}