JWT令牌技术

[复制链接]
admin 发表于 2025-9-14 08:10:07 | 显示全部楼层 |阅读模式
1). 首先我们先来实现JWT令牌的生成。要想使用JWT令牌,需要先引入JWT的依赖:

  1. <!-- JWT依赖-->
  2. <dependency>
  3.     <groupId>io.jsonwebtoken</groupId>
  4.     <artifactId>jjwt</artifactId>
  5.     <version>0.9.1</version>
  6. </dependency>
复制代码
在引入完JWT来赖后,就可以调用工具包中提供的API来完成JWT令牌的生成和校验。工具类:Jwts

2). 生成JWT代码实现:
  1. @Test
  2. public void testGenJwt() {
  3.     Map<String, Object> claims = new HashMap<>();
  4.     claims.put("id", 10);
  5.     claims.put("username", "itheima");

  6.     String jwt = Jwts.builder().signWith(SignatureAlgorithm.HS256, "aXRjYXN0")
  7.         .addClaims(claims)
  8.         .setExpiration(new Date(System.currentTimeMillis() + 12 * 3600 * 1000))
  9.         .compact();

  10.     System.out.println(jwt);
  11. }
复制代码

运行测试方法:
  1. eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjcyNzI5NzMwfQ.fHi0Ub8npbyt71UqLXDdLyipptLgxBUg_mSuGJtXtBk
复制代码

3). 实现了JWT令牌的生成,下面我们接着使用Java代码来校验JWT令牌(解析生成的令牌):

  1. @Test
  2. public void testParseJwt() {
  3.     Claims claims = Jwts.parser().setSigningKey("aXRjYXN0")
  4.         .parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MTAsInVzZXJuYW1lIjoiaXRoZWltYSIsImV4cCI6MTcwMTkwOTAxNX0.N-MD6DmoeIIY5lB5z73UFLN9u7veppx1K5_N_jS9Yko")
  5.         .getBody();
  6.     System.out.println(claims);
  7. }
复制代码
运行测试方法:
  1. {id=10, username=itheima, exp=1701909015}
复制代码

令牌解析后,我们可以看到id和过期时间,如果在解析的过程当中没有报错,就说明解析成功了。


完整生成JWT令牌和解析案例:
  1. @Test
  2. public void genJwt(){
  3.     Map<String, Object> claims = new HashMap<>();
  4.     claims.put("id", 10);
  5.     claims.put("username", "itheima");

  6.     String jwt = Jwts.builder().signWith(SignatureAlgorithm.HS256, "aXRjYXN0")
  7.         .addClaims(claims)
  8.         .setExpiration(new Date(System.currentTimeMillis() + 60 * 1000)) //有效期60s
  9.         .compact();
  10.     System.out.println(jwt);
  11.     //输出结果:eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjczMDA5NzU0fQ.RcVIR65AkGiax-ID6FjW60eLFH3tPTKdoK7UtE4A1ro
  12. }

  13. @Test
  14. public void parseJwt(){
  15.     Claims claims = Jwts.parser()
  16.         .setSigningKey("aXRjYXN0")//指定签名密钥
  17.         .parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjczMDA5NzU0fQ.RcVIR65AkGiax-ID6FjW60eLFH3tPTKdoK7UtE4A1ro")
  18.         .getBody();

  19.     System.out.println(claims);
  20. }
复制代码

实践开发项目:
1,登录成功后创建JWT令牌
  1. @PostMapping("/login")
  2.     @ApiOperation(value = "员工登录接口")
  3.     public Result<EmployeeLoginVO> login(@RequestBody EmployeeLoginDTO employeeLoginDTO) {
  4.         log.info("员工登录:{}", employeeLoginDTO);

  5.         Employee employee = employeeService.login(employeeLoginDTO);

  6.         //登录成功后,生成jwt令牌
  7.         Map<String, Object> claims = new HashMap<>();
  8.         claims.put(JwtClaimsConstant.EMP_ID, employee.getId());
  9. //        claims.put("id", employee.getId());
  10. //        claims.put("username", employee.getUsername());
  11.         String token = JwtUtil.createJWT(
  12.                 jwtProperties.getAdminSecretKey(),
  13.                 jwtProperties.getAdminTtl(),
  14.                 claims);

  15.         EmployeeLoginVO employeeLoginVO = EmployeeLoginVO.builder()
  16.                 .id(employee.getId())
  17.                 .userName(employee.getUsername())
  18.                 .name(employee.getName())
  19.                 .token(token)
  20.                 .build();

  21.         return Result.success(employeeLoginVO);
  22.     }
复制代码
1.jpg

2,JWT令牌拦截器拦截令牌,并解析内容
  1. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  2.         // 获取当前线程ID
  3.         long threadId = Thread.currentThread().getId();
  4.         System.out.println("线程ID:" + threadId);
  5.         //判断当前拦截到的是Controller的方法还是其他资源
  6.         if (!(handler instanceof HandlerMethod)) {
  7.             //当前拦截到的不是动态方法,直接放行
  8.             return true;
  9.         }

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

  12.         //2. 判断令牌是否存在,如果不存在,返回错误结果(未登录)。
  13.         if(!StringUtils.hasLength(token)){ //jwt为空
  14.             log.info("获取到jwt令牌为空, 返回错误结果");
  15.             response.setStatus(HttpStatus.SC_UNAUTHORIZED);
  16.             return false;
  17.         }

  18.         //3、校验令牌
  19. //        校验过程:
  20. //        使用 JwtUtil.parseJWT 方法解析 JWT 令牌
  21. //        传入两个参数:
  22. //        jwtProperties.getAdminSecretKey():获取管理员密钥,用于验证签名
  23. //        token:客户端传递的 JWT 令牌
  24. //        如果 token 有效且签名正确,会返回 Claims 对象
  25. //        如果 token 无效、过期或签名不正确,则会抛出异常
  26.         try {
  27.             log.info("jwt校验:{}", token);
  28.             Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
  29.             Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());
  30.             log.info("当前员工id:", empId);
  31.             // 将当前登录用户的ID保存到当前线程的LocalThread中
  32.             BaseContext.setCurrentId(empId);
  33.             //3、通过,放行
  34.             return true;
  35.         } catch (Exception ex) {
  36.             //4、不通过,响应401状态码
  37.             response.setStatus(401);
  38.             return false;
  39.         }
  40.     }
复制代码
2.jpg


完整代码:
sky-take-out.zip (72.67 KB, 下载次数: 0, 价格: 10 金钱)

如何获得当前登录用户ID,如何传值到service,线程局部变量ThreadLocal解决
https://www.zidiu.com/thread-44-1-1.html
网站建设,公众号小程序开发,多商户单商户小程序制作,高端系统定制开发,App软件开发联系我们【手机/微信:17817817816
微信扫码

网站建设,公众号小程序开发,商城小程序,系统定制开发,App软件开发等

粤ICP备2024252464号

在本版发帖
微信扫码
QQ客服返回顶部
快速回复 返回顶部 返回列表