SpringBoot中JWT详解,底层原理及生成验证实例。

06-01 1744阅读

目录

JWT

什么是 JWT?

在 Spring Boot 中使用 JWT 的场景

JWT 底层原理

1. 令牌生成

2. 令牌验证

3. 签名算法

Spring Boot 中 JWT 的实现示例

JWT 的优缺点

安全注意事项

实例演示:

导入Maven坐标

JwtProperties配置类

SpringBoot中JWT详解,底层原理及生成验证实例。
(图片来源网络,侵删)

application.yml配置文件

JwtTokenUserInterceptor拦截器

SpringBoot中JWT详解,底层原理及生成验证实例。
(图片来源网络,侵删)

WebMvcConfiguration注册自定义拦截器

Controller层登录生成token

SpringBoot中JWT详解,底层原理及生成验证实例。
(图片来源网络,侵删)

JWT

什么是 JWT?

JWT (JSON Web Token) 是一种开放标准 (RFC 7519),用于在各方之间安全地传输信息作为 JSON 对象。它通常用于身份验证和信息交换。

JWT 由三部分组成,用点(.)分隔:

  1. Header - 包含令牌类型和使用的哈希算法

  2. Payload - 包含声明(claims),即有关实体(通常是用户)和其他数据的声明

  3. Signature - 用于验证消息在传输过程中没有被更改

格式:xxxxx.yyyyy.zzzzz

在 Spring Boot 中使用 JWT 的场景

  1. 身份验证:用户登录后,服务器生成 JWT 返回给客户端,客户端在后续请求中携带该令牌

  2. 信息交换:安全地在各方之间传输信息

  3. 无状态认证:特别适合 RESTful API,服务端不需要保存会话信息

  4. 跨域认证:适用于单点登录(SSO)场景

  5. 移动应用认证:比传统的 cookie-session 更适合移动端

JWT 底层原理

1. 令牌生成

  1. 用户提供凭据(如用户名密码)登录

  2. 服务器验证凭据

  3. 服务器创建 JWT:

    • Header: {"alg": "HS256", "typ": "JWT"}

    • Payload: {"sub": "1234567890", "name": "John Doe", "iat": 1516239022}

    • Signature: 使用密钥对编码后的 header 和 payload 进行签名

    • 服务器返回 JWT 给客户端

2. 令牌验证

  1. 客户端在请求头中发送 JWT (通常在 Authorization 头中)

  2. 服务器提取 JWT

  3. 服务器验证签名是否有效

  4. 如果有效,服务器使用 payload 中的信息处理请求

3. 签名算法

JWT 通常使用以下算法之一进行签名:

  • HMAC + SHA256 (HS256)

  • RSA + SHA256 (RS256)

  • ECDSA + SHA256 (ES256)、

    Spring Boot 中 JWT 的实现示例

    // 添加依赖
    // implementation 'io.jsonwebtoken:jjwt:0.9.1'
    import io.jsonwebtoken.Jwts;
    import io.jsonwebtoken.SignatureAlgorithm;
    import io.jsonwebtoken.Claims;
    public class JwtUtil {
        private static final String SECRET_KEY = "your-secret-key";
        private static final long EXPIRATION_TIME = 864_000_000; // 10天
        
        // 生成JWT
        public static String generateToken(String username) {
            return Jwts.builder()
                    .setSubject(username)
                    .setIssuedAt(new Date())
                    .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
                    .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                    .compact();
        }
        
        // 验证JWT
        public static Boolean validateToken(String token, String username) {
            final String usernameInToken = extractUsername(token);
            return (username.equals(usernameInToken) && !isTokenExpired(token));
        }
        
        // 从JWT中提取用户名
        public static String extractUsername(String token) {
            return getClaims(token).getSubject();
        }
        
        // 检查JWT是否过期
        public static Boolean isTokenExpired(String token) {
            return getClaims(token).getExpiration().before(new Date());
        }
        
        // 从JWT中获取claims
        private static Claims getClaims(String token) {
            return Jwts.parser()
                    .setSigningKey(SECRET_KEY)
                    .parseClaimsJws(token)
                    .getBody();
        }
    }

    JWT 的优缺点

    优点:

    • 无状态,服务器不需要存储会话信息

    • 适合分布式系统和微服务架构

    • 可以包含自定义的 claims

    • 跨语言支持

      缺点:

      • 令牌一旦签发,在有效期内无法撤销(除非使用黑名单机制)

      • 如果被盗用,攻击者可以在有效期内滥用

      • 负载大小比 session ID 大

        安全注意事项

        1. 始终使用 HTTPS

        2. 不要将敏感信息存储在 JWT payload 中

        3. 设置合理的过期时间

        4. 考虑使用刷新令牌机制

        5. 对于高安全性应用,可以考虑使用短期令牌+黑名单机制

        实例演示:

        导入Maven坐标
            io.jsonwebtoken
            jjwt
            ${jjwt}
        
        JwtProperties配置类
        import lombok.Data;
        import org.springframework.boot.context.properties.ConfigurationProperties;
        import org.springframework.stereotype.Component;
        ​
        @Component
        @ConfigurationProperties(prefix = "sky.jwt")
        @Data
        public class JwtProperties {
            /**
             * 用户端微信用户生成jwt令牌相关配置
             */
            private String userSecretKey;
            private long userTtl;
            private String userTokenName;
        ​
        }
        application.yml配置文件
        sky:
          jwt:
            #设置jwt签名加密时使用的密钥
            user-secret-key: itcast
            # 设置jwt过期时间
            user-ttl: 7200000
            # 设置前端传递过来的令牌名称
            user-token-name: authentication
        JwtTokenUserInterceptor拦截器
        /**
         * jwt令牌校验的拦截器
         */
        @Component
        @Slf4j
        public class JwtTokenUserInterceptor implements HandlerInterceptor {
        ​
            @Autowired
            private JwtProperties jwtProperties;
        ​
            /**
             * 校验用户端的jwt
             *
             * @param request
             * @param response
             * @param handler
             * @return
             * @throws Exception
             */
            public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
                //System.out.println("当前线程的id:"+Thread.currentThread().getId());
                //判断当前拦截到的是Controller的方法还是其他资源
                if (!(handler instanceof HandlerMethod)) {
                    //当前拦截到的不是动态方法,直接放行
                    return true;
                }
        ​
                //1、从请求头中获取令牌
                String token = request.getHeader(jwtProperties.getUserTokenName());
        ​
                //2、校验令牌
                try {
                    log.info("用户端jwt校验:{}", token);
                    Claims claims = JwtUtil.parseJWT(jwtProperties.getUserSecretKey(), token);
                    Long userId = Long.valueOf(claims.get(JwtClaimsConstant.USER_ID).toString());
                    log.info("当前用户id:", userId);
                    BaseContext.setCurrentId(userId);
                    //3、通过,放行
                    return true;
                } catch (Exception ex) {
                    //4、不通过,响应401状态码
                    response.setStatus(401);
                    return false;
                }
            }
        }
        WebMvcConfiguration注册自定义拦截器
        /**
         * 配置类,注册web层相关组件
         */
        @Configuration
        @Slf4j
        public class WebMvcConfiguration extends WebMvcConfigurationSupport {
            @Autowired
            private JwtTokenUserInterceptor jwtTokenUserInterceptor;
        ​
            /**
             * 注册自定义拦截器
             *
             * @param registry
             */
            protected void addInterceptors(InterceptorRegistry registry) {
                log.info("开始注册自定义拦截器...");
                registry.addInterceptor(jwtTokenUserInterceptor)
                        .addPathPatterns("/user/**")
                        .excludePathPatterns("/user/user/login")
                        .excludePathPatterns("user/shop/status");
            }
        }
        Controller层登录生成token
        @RestController
        @RequestMapping("/user/user")
        @Slf4j
        @RequiredArgsConstructor  // Lombok 自动生成构造函数
        @Api(tags = "C端用户相关接口")
        public class UserController {
            private final UserService userService;
            private final JwtProperties jwtProperties;
            /**
             * 微信登录
             * @param userLoginDTO
             * @return
             */
            @PostMapping("/login")
            @ApiOperation("微信登录")
            public Result login(@RequestBody UserLoginDTO userLoginDTO){
                log.info("微信用户登录:{}",userLoginDTO.getCode());
                //微信登录
                User user = userService.wxLogin(userLoginDTO);
                //为微信用户生成jwt令牌
                Map claims = new HashMap();
                claims.put(JwtClaimsConstant.USER_ID,user.getId());
                String token = JwtUtil.createJWT(jwtProperties.getUserSecretKey(),jwtProperties.getUserTtl(),claims);
                UserLoginVO userLoginVO = UserLoginVO.builder()
                        .id(user.getId())
                        .openid(user.getOpenid())
                        .token(token)
                        .build();
                return Result.success(userLoginVO);
            }
        }
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

目录[+]

取消
微信二维码
微信二维码
支付宝二维码