餐饮智能互联平台技术要点——JWT拦截器

简介

实现一个拦截器(Interceptor),用于在处理HTTP请求之前对JWT(JSON Web Token)令牌进行校验。

JWT是一种用于身份验证和授权的令牌标准,通常包含用户信息和权限等信息,用于在客户端和服务器之间传递身份信息。

实现思路

20230903152750

代码实现

在sky-server模块中,com.sky.interceptor.JwtTokenAdminInterceptor。

    /**
     * 校验jwt
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //判断当前拦截到的是Controller的方法还是其他资源
        if (!(handler instanceof HandlerMethod)) {
            //当前拦截到的不是动态方法,直接放行
            return true;
        }

        //1、从请求头中获取令牌 jwtProperties.getAdminTokenName()获取为token
        String token = request.getHeader(jwtProperties.getAdminTokenName());

        //2、校验令牌
        try {
            log.info("jwt校验:{}", token);
            Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
            Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());
            log.info("当前员工id:", empId);
            BaseContext.setCurrentId(empId);
            //3、通过,放行
            return true;
        } catch (Exception ex) {
            //4、不通过,响应401状态码
            response.setStatus(401);
            return false;
        }
    }

在sky-common模块中,com.sky.controller.utils.JwtUtil。

    /**
     * Token解密
     *
     * @param secretKey jwt秘钥 此秘钥一定要保留好在服务端, 不能暴露出去, 否则sign就可以被伪造, 如果对接多个客户端建议改造成多个
     * @param token     加密后的token
     * @return
     */
    public static Claims parseJWT(String secretKey, String token) {
        // 得到DefaultJwtParser
        Claims claims = Jwts.parser()
                // 设置签名的秘钥
                .setSigningKey(secretKey.getBytes(StandardCharsets.UTF_8))
                // 设置需要解析的jwt
                .parseClaimsJws(token).getBody();
        return claims;
    }

这段代码实现了一个JWT令牌的验证拦截器,用于保护某些Controller方法,确保只有携带有效令牌的请求能够访问它们。如果令牌验证成功,会将员工ID设置到当前线程的上下文中,以便后续的代码可以使用该信息。如果令牌验证失败,请求将被拒绝。这是一种常见的身份验证和授权机制,用于保护Web应用程序的安全性。

代码解读

  • JwtTokenAdminInterceptor 类是Spring框架的组件(Component),它实现了 HandlerInterceptor 接口,用于拦截请求并在请求处理前进行JWT令牌的验证。

  • preHandle 方法是拦截器的主要方法,在请求到达Controller方法之前调用。该方法接受三个参数:HttpServletRequest request 表示HTTP请求对象,HttpServletResponse response 表示HTTP响应对象,Object handler 表示处理请求的方法对象

  • 在方法开始处,通过判断 handler 是否是 HandlerMethod 的实例,来确定当前拦截的是Controller的方法还是其他资源。如果不是Controller的方法,直接放行,不进行JWT令牌的校验。如果 handler 是 HandlerMethod 的实例,说明拦截到的是Controller的方法,接下来进行JWT令牌的校验。

  • 从HTTP请求头中获取JWT令牌。

  • 尝试解析JWT令牌,如果解析成功,会得到JWT中的声明(Claims),并从中提取出员工ID。

  • 如果JWT解析成功,将员工ID设置到当前线程的上下文中,以便后续的请求可以访问该员工ID。这通常是为了在请求处理过程中获取当前用户的身份信息。

  • 最后,如果JWT令牌验证通过,preHandle 方法返回 true,允许请求继续执行Controller方法;如果JWT令牌验证失败,将HTTP响应状态码设置为401(未授权),并返回 false,拒绝请求继续执行。

HandlerMethod详解

简介

在Spring框架中,HandlerMethod 表示一个处理请求的具体Controller方法。它是Spring MVC中的一个类,用于描述和包装处理HTTP请求的Controller方法的相关信息,包括Controller的类实例、方法名、方法参数等。

它通常在请求被拦截器、拦截器链或处理器适配器中使用,用于确定应该调用哪个Controller方法来处理请求。

示例

例如,在上述拦截器中,可以使用 instanceof 来检查 handler 是否是 HandlerMethod 的实例,以确定当前拦截的是Controller的方法:

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    if (handler instanceof HandlerMethod) {
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        // 确定拦截到的是Controller的方法
        String methodName = handlerMethod.getMethod().getName();
        String className = handlerMethod.getBeanType().getName();
        System.out.println("拦截到的Controller方法:" + className + "." + methodName);
    }
    // 继续处理或放行请求
    return true;
}

在上面的代码中,我们首先检查 handler 是否是 HandlerMethod 的实例,如果是,就可以获取有关该Controller方法的信息,如方法名和类名等。

通过 HandlerMethod,Spring MVC能够更精确地调用匹配的Controller方法,以确保请求被正确处理。这在处理RESTful API请求时尤其有用,因为一个Controller类中可能有多个方法,根据请求的URL和HTTP方法的不同来决定调用哪个方法。

posted @ 2023-09-03 16:08  岸南  阅读(121)  评论(0)    收藏  举报