登录校验功能

19 阅读5分钟

JWT

全称:JSON Web Token:定义了一种简洁的(就是个字符串)、自包含(可以存信息)的格式,用于在通信双方以json数据格式安全的传输信息。由于数字签名的存在,这些信息是可靠的,不会被篡改的

由三个部分组成,点分字符串形式,1,2由Base64编码得到,3由1中指定的算法算出来:

  1. Header(头):记录令牌类型、签名算法等。例如:{"algg":"HS256", type": "JWT"}
  2. Payload(有效载荷):携带一些自定义信息、默认信息等。例如:{"id":"1","username":"Tom"}
  3. Signature(签名):防止Token被篡改、确保安全性。将header、payload,并加入指定秘钥,通过指定签名算法计算而来。

生成JWT

  1. 引入依赖

    io.jsonwebtoken
    jjwt
    0.9.1

  1. 使用提供的工具类JWTs生成
String jwt=Jwts.builder()
.signWith(SignatureAlgorithm.H5256,"密钥")//签名算法会
.setClaims(claims)//自定义内容(载荷)
.setExpiration(new Date(System.currentTimeMillis() + 12*3600*10000)//有效期,注意Date中构造参数为毫秒值
.compact();

解析JWT

Claims claims = Jwts.parser()
    .setSigningKey("密钥")
    .parseClaimsJws("JWT字符串")
    .getBody();// 拿到第二部分负载

场景:登录认证

  1. 登录成功后,生成令牌并返回给前端
  2. 后续每个请求,都要携带JWT令牌
  3. 系统在每次请求处理之前,先校验令牌,通过后,再处理

常用Filter或者Interceptor进行统一处理

统一检验token-Filter

Filter是javaWeb三大组件(Servlet、Filter、Listener)之一

Filter准备工作

  1. 在启动类上添加@ServletComponentScan注解
  2. 创建一个Filter类实现javax.servlet.Filter接口
  3. Filter类上加@WebFilter(urlPatterns = "),注解,配置拦截资源的路径。
  4. 有三个方法可以实现,可以只实现doFilter:
    1. init(FilterConfig filterConfig):初始化方法,只会调用一次
    2. doFilter(ServletRequest request, ServletResponse response,FilterChain chain)
    3. destory:销毁方法,服务器销毁时调用,只调用一次

Filter拦截路径

通过@WebFilter(urlPatterns = "xxx")配置拦截路径,有 3 种常见方式:

拦截类型拦截路径拦截规则
具体路径拦截/login仅访问/login时拦截
目录拦截/books/*访问/books下所有资源时拦截
全部拦截/*访问所有资源时拦截
Filter执行流程
  1. 请求到达 Filter:浏览器请求先被 Filter 拦截
  2. 放行前逻辑:执行chain.doFilter()之前的代码(如日志、权限校验)
  3. 放行到 web 资源:通过chain.doFilter()将请求传递给接口
  4. 资源处理并返回:web 资源处理请求后,响应回到 Filter
  5. 放行后逻辑:执行chain.doFilter()之后的代码(如统一响应处理)

注意事项:放行和return不同,他是会回来执行下面的代码的,所以不想让让他执行下面的就多加一个return

过滤器链

  • 介绍:一个web应用中,可以配置多个过滤器,这多个过过滤器就形成了一个过滤器链。
  • 顺序:注解配置的Filter,优先级是按照过滤器类名(字符串)的自然排序

登录校验Filter-登录校验流程

  1. 在doFilter(ServletRequest request, ServletResponse response,FilterChain chain)方法中
  2. 需要将参数强转为HttpServletRequest以及HttpServletResponse
  3. 判断请求若是登录操作,不拦截直接放行
  4. 获取请求头中的令牌(token)
  5. 判断令牌是否存在,如果不存在,返回错误结果(未登录)
  6. 解析token,如果解析失败,返回错误结果(未登录)
  7. 放行

注意:其中返回错误结果提示前端要自己写,如下

Result error = Result.error("NOT_LOGIN");
//手动转换对象->json
String notLogin = JSONObject.toJSONString(error)
resp.getWriter().write(notLogin);

统一检验token-Interceptor

Spring相架中提供的,用来动态拦截控制器方法的执行,类似于过滤器。

作用:拦截请求,在指定的方法调用前后,根据业务需要执行预先设定的代码。

Interceptor准备工作

  1. 创建一个Interceptor类实现HandlerInterceptor接口
  2. 有三个方法可以实现,这三个方法都有默认实现:
    1. boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler):controller前执行,返回值true放行,false不放行
    2. postHandle(HttpServletRequest req, HttpServletResponse resp, Object handler, MModelAndView modelAndView):controller后执行
    3. afterCompletion (HttpServletRequesit req, HttpServletResponse resp, Object handller, Exception ex):视图渲染完毕后执行,最后执行
  3. 注册拦截器: 首先用@Component注解将拦截器给IOC容器管理,创建一个配置类并加上@Configuration,实现WebMvcConfigurer接口,示例代码如下
    @Configuration
    public class WebConfig implements WebMvcConfigurer {
        @Autowired
        private LoginCheckInterceptor loginCheckInteerceptor
            
        @Override
        public void addInterceptors((InterceptorRegistry registry) {
            registry
            .addInterceptor(loginCheckInterceptor)
            .addPathPatterns("/**") //需要拦截哪些资源
            .excludePathPatterns("/login"); //不需要拦截哪些资源;
        }
    }
    

Interceptor拦截路径

拦截路径含义匹配示例
/*一级路径能配/depts,不能配/depts/1
/**任意级路径能配/depts,/depts/1,/depts/1/2
/depts/*/depts下一级路径能配/depts/1,不能配/depts/1/2
/depts/**/depts下任意级路径能配/depts,/depts/1,/depts/1/2
Interceptor执行流程
  1. 请求阶段

    • 浏览器发请求 → 进入 Filter
    • Filter 执行doFilter()放行前逻辑 → 放行到 DispatcherServlet
    • DispatcherServlet 转发 → Interceptor 执行preHandle() → 进入 Controller 执行业务
  2. 响应阶段

    • Controller 处理完成 → Interceptor 执行postHandle()
    • 请求完全完成 → Interceptor 执行afterCompletion() → 回到 DispatcherServlet
    • 回到 Filter → 执行doFilter()放行后逻辑 → 响应返回浏览器

Filter 与 Interceptor的不同点

  • 接口规范不同:
    • 过滤器需要实现Filter接口
    • 拦截器需要实现Handlerintercepto接口
  • 拦截范围不同:
    • 过滤器Filter会拦截所有的资源
    • Interceptor只会拦截Spring环境中的资源

登录校验Interceptor-登录校验流程

  1. boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler)中
  2. 获取请求头中的令牌(token)
  3. 判断令牌是否存在,如果不存在,返回错误结果(未登录)并return false;
  4. 解析token,如果解析失败,返回错误结果(未登录)并return false;
  5. return true;