目录
一、登录认证问题
在未登录的情况下,不应该访问到其他资源,而是应该回到登录页面
使用jwt令牌技术(令牌就是一段字符串)
使用:
1、首先需要在pom文件中引入jwt令牌的坐标
2、调用api进行使用(将来使用的时候都是使用已经提供好的工具类)
public class JwtUtil {
private static long tokenExpiration = 60 * 60 * 1000L; //一个小时
private static SecretKey tokenSignKey = Keys.hmacShaKeyFor("zyx5201314zyx5211314zyx520521zyx".getBytes());
public static String createToken(Long userId, String username) {
String token = Jwts.builder().
setSubject("USER_INFO").
setExpiration(new Date(System.currentTimeMillis() + tokenExpiration)).
claim("userId", userId).
claim("username", username).
signWith(tokenSignKey, SignatureAlgorithm.HS256).
compact();
return token;
}
// 校验JWT合法性的逻辑
public static Claims parseToken(String token) {
if(token == null){
throw new LeaseException(ResultCodeEnum.ADMIN_LOGIN_AUTH);
}
try{
JwtParser jwtParser = Jwts.parserBuilder().setSigningKey(tokenSignKey).build();
Claims claims = jwtParser.parseClaimsJws(token).getBody();
return claims;
}catch (ExpiredJwtException e){ //token过期
throw new LeaseException(ResultCodeEnum.TOKEN_EXPIRED);
}catch (JwtException e){ //异常的父类
throw new LeaseException(ResultCodeEnum.TOKEN_INVALID); //token非法
}
}
}
以后在登录成功的时候生成一个jwt令牌token
实例:
将来我们在调用其它接口的时候,需要验证jwt令牌token的合法性(多个接口都需要验证,我们可以使用拦截器完成校验)
二、拦截器
1、首先定义一个类实现HandlerInterceptor接口并且重写preHandle方法
实例:我们在方法里面校验令牌
2、写一个web配置类实现webMvcConfigurer接口,并且在addInterceptors方法(添加拦截器)里面通过@Autowired注解获取并把我们刚刚编写的拦截器给它注册进去
实例(登录和注册的接口不进行拦截):
三、ThreadLocal
3.1 使用场景
在每个线程内需要保存全局变量(例如在拦截器中获取用户信息),可以让不同方法直接使用,避免参数传递的麻烦。
1、用来存储数据:set()和get()
2、使用ThreadLocal存储的数据是线程安全的
3、用完使用remove方法进行释放
3.2 使用
使用threadlocal工具类
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();
}
}
在拦截器中存储用户的数据
在接口中获取ThreadLocal存储的数据
ThreadLocal的清除(防止内存泄漏)
场所:请求发过来的时候,我们解析它携带的token并且把它存到ThreadLocal里面,接下来这个请求放行了之后,在响应完成之后这一次请求结束了就不再使用了,就可以把它移除掉
我们可以在拦截器LoginInterceptor类中的afterCompletion方法中清空ThreadLocal中的数据
// 清理线程池
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
LoginUserHolder.clear();
}