Bootstrap

JavaWeb学习日结

今天完成了登录模块的功能。了解了三种会话技术及其优缺点,然后掌握了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("/**");
    }
}

;