今天完成了登录模块的功能。了解了三种会话技术及其优缺点,然后掌握了JWT令牌的生成、Filter过滤器以及Interceptor拦截器的实现方法。
会话追踪技术:
一、Cookie:
优点:HTTP协议中支持的技术
缺点:移动端无法使用Cookie;不安全,用户可以在客户端(浏览器)自己禁用Cookie;Cookie不能跨域。
二、Session:
优点:存储在服务端,安全
缺点:服务器集群环境下无法直接使用Session;Cookie的其他所有缺点。
三、令牌:
优点:支持PC端和移动端;解决集群环境下的认证问题;减轻服务端储存压力。
缺点:需要自己代码实现。
创建一个工具类定义Jwt令牌的生成和解析方法,在登录成功的实现方法上生成令牌随结果响应给前端。
public class JwtUtils {
private static String signKey = "**********";//Base64编码后的密钥
private static Long expire = 43200000L;
/**
* 生成JWT令牌
* @return
*/
public static String generateJwt(Map<String,Object> claims){
String jwt = Jwts.builder()
.addClaims(claims)
.signWith(SignatureAlgorithm.HS256, signKey)
.setExpiration(new Date(System.currentTimeMillis() + expire))
.compact();
return jwt;
}
/**
* 解析JWT令牌
* @param jwt JWT令牌
* @return JWT第二部分负载 payload 中存储的内容
*/
public static Claims parseJWT(String jwt){
Claims claims = Jwts.parser()
.setSigningKey(signKey)
.parseClaimsJws(jwt)
.getBody();
return claims;
}
}
Filter过滤器 :
@Slf4j
@WebFilter(urlPatterns = "/*")
public class TokenFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
//获取到请求路径
String requestURI = request.getRequestURI();
//判断是否是登录请求,如果请求路径中包含/login,则放行
if (requestURI.contains("/login")) {
filterChain.doFilter(request, response);
return;
}
//如果不是登录请求,获取请求头中的token
String token = request.getHeader("token");
//如果token为空,则返回401状态码,提示用户未登录
if (token == null || token.isEmpty()) {
log.info("令牌为空,响应401");
response.setStatus(401);
return;
}
//如果token不为空,则解析token,如果解析失败,则返回401状态码
try {
JwtUtils.parseJWT(token);
} catch (Exception e) {
log.info("令牌非法,响应401");
response.setStatus(401);
return;
}
//如果解析成功,则放行
log.info("令牌合法,放行");
filterChain.doFilter(request, response);
}
}
@WebFilter(urlPatterns = "/*")指定了拦截所有路径的请求,在实现逻辑中层层放行。
注意在启动类上添加注解 @ServletComponentScan,Spring才能扫描到servlet中的组件并使用,否则Filter过滤器不起作用。
Interceptor拦截器:
@Slf4j
@Component
public class TokenInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//获取到请求路径
String requestURI = request.getRequestURI();
//判断是否是登录请求,如果请求路径中包含/login,则放行
if (requestURI.contains("/login")) {
log.info("登录请求,放行");
return true;
}
//如果不是登录请求,获取请求头中的token
String token = request.getHeader("token");
//如果token为空,则返回401状态码,提示用户未登录
if (token == null || token.isEmpty()) {
log.info("令牌为空,响应401");
response.setStatus(401);
return false;
}
//如果token不为空,则解析token,如果解析失败,则返回401状态码
try {
JwtUtils.parseJWT(token);
} catch (Exception e) {
log.info("令牌非法,响应401");
response.setStatus(401);
return false;
}
//如果解析成功,则放行
log.info("令牌合法,放行");
return true;
}
}
@Component注解让Ioc容器识别,方便在配置类中自动注入。
创建一个配置类实现Interceptor拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private TokenInterceptor tokenInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(tokenInterceptor).addPathPatterns("/**");
}
}