JWT 实战:在 Spring Boot 中的使用

server/2025/2/2 19:26:52/

文章目录

  • 一、JWT简介
  • 二、JWT 的结构
  • 三、JWT 的生成过程
  • 四、JWT 验证过程
  • 五、JWT 的应用场景
  • 六、JWT的实现
    • 6.1 登录接口
    • 6.2 校验 Token 接口
    • 6.3 `jwtUtil` 类
  • 七、总结

一、JWT简介

JWT(JSON Web Token)是一种用于客户端和服务器之间安全传输信息的开放标准(RFC 7519)。JWT 的目的是通过一种 compact、URL-safe 的方式传递信息,以便在 web 应用中广泛使用,尤其是在用户认证和授权中。

二、JWT 的结构

JWT 由三部分组成,每部分之间用 . 进行分隔,格式为: header.payload.signature

  1. Header(头部):描述 JWT 的元数据,通常包含令牌类型(JWT)和签名算法(例如:HS256RS256),头部通常使用 Base64 编码后成为 JWT 的第一部分。
  2. Payload(负载):包含用户信息或其他声明(Claims)。这里的内容是 JSON 格式的声明,可以是公开的(如 name, exp)或私有的。
  3. Signature(签名):用来验证消息的完整性,防止数据被篡改。它是通过 Header 和 Payload 以及密钥(secret)一起生成的。

三、JWT 的生成过程

JWT 的生成通常会通过以下步骤:

  1. Header:指定签名算法(通常是 HMAC SHA256 或 RSA)。

    {"alg": "HS256","typ": "JWT"
    }
    
  2. Payload:包含具体的声明信息,如:

    • sub(Subject):标识该 JWT 的主体(通常是用户的 ID)。
    • exp(Expiration):标识 JWT 的过期时间。
    • iat(Issued At):标识 JWT 的签发时间。
    • iss(Issuer):标识 JWT 的签发者。
    • aud(Audience):指定此 JWT 的接收者。

    示例 Payload:

    {"sub": "1234567890","name": "John Doe","iat": 1516239022
    }
    
  3. Signature:使用 Header 和 Payload 以及签名密钥生成签名。

    • 如果使用 HMAC SHA256 算法,则签名生成过程为:
      HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload),secret)
      
  4. 最终生成的 JWT:将 Header、Payload 和 Signature 连接起来,以 . 分隔。

    header.payload.signature
    

四、JWT 验证过程

JWT 的验证主要是检查签名是否有效以及 exp(过期时间)等是否符合要求。

  1. 从请求头中提取 JWT。
  2. 使用与生成 JWT 时相同的算法、密钥来验证签名是否有效。
  3. 如果签名有效,检查 JWT 的有效期(exp),以及是否存在其他不符合要求的声明。
  4. 如果有效,服务器允许访问该资源;如果无效,返回错误信息。

五、JWT 的应用场景

  • 认证(Authentication):JWT 最常见的应用场景是身份认证。例如,用户登录时,服务器验证其用户名和密码后生成一个 JWT,并将其返回给客户端。客户端在之后的每次请求中将该 JWT 放入 HTTP 请求头(Authorization)。

  • 授权(Authorization):JWT 也常用于访问控制。例如,通过 JWT 可以携带用户的权限信息,确保用户有权限访问某些资源。

  • 信息交换(Information Exchange):JWT 可以安全地传递信息,因为它是自包含的,信息在签发时已经被加密验证,因此不容易篡改。

六、JWT的实现

6.1 登录接口

/login 接口用于用户登录并生成 JWT:

java">@PostMapping("/login")
public Result login(@RequestBody LoginForm loginForm, HttpSession session){// 验证验证码String code = (String) this.redisTemplate.opsForValue().get(loginForm.getUuid());if(code == null || !code.equals(loginForm.getCaptcha())) {return Result.error("验证码错误");}// 验证用户名和密码QueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.eq("username", loginForm.getUsername());User user = this.userService.getOne(queryWrapper);if(user == null || !SecureUtil.sha256(loginForm.getPassword()).equals(user.getPassword())) {return Result.error("用户名或密码错误");}// 检查用户是否被锁定if(user.getStatus() == 0) {return Result.error("账号已被锁定,请联系管理员");}// 登录成功,生成 Tokensession.setAttribute("user", user);String token = this.jwtUtil.createToken(String.valueOf(user.getUserId()));this.redisTemplate.opsForValue().set("communityuser-" + user.getUserId(), token, jwtUtil.getExpire());Map<String, Object> map = new HashMap<>();map.put("token", token);map.put("expire", jwtUtil.getExpire());// 返回生成的 tokenreturn Result.ok().put("data", map);
}

如果登录成功,生成一个 JWT Token,并存储到 Redis 中。返回给客户端该 token 和过期时间。

6.2 校验 Token 接口

/checkToken 接口用于验证客户端传来的 token 是否有效:

java">@GetMapping("/checkToken")
public Result checkToken(HttpServletRequest request){String token = request.getHeader("token");boolean result = this.jwtUtil.checkToken(token);if(result) return Result.ok().put("status", "ok");return Result.ok().put("status", "error");
}
  1. 提取 Token:从请求头中提取 token
  2. 验证 Token:调用 jwtUtil.checkToken 方法来验证 token 是否有效。
  3. 返回验证结果:如果 token 有效,返回 "status": "ok";如果无效,返回 "status": "error"

6.3 jwtUtil

jwtUtil 类封装了生成和验证 JWT 的操作,通常包括以下方法:

  1. createToken:生成一个新的 JWT,包含用户信息和过期时间。

    java">public String createToken(String userId) {return Jwts.builder().setSubject(userId).setIssuedAt(new Date()).setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60))  // 设置过期时间.signWith(SignatureAlgorithm.HS256, secretKey)  // 使用密钥进行签名.compact();
    }
    
  2. checkToken:验证传入的 token 是否有效。

    java">public boolean checkToken(String token) {try {Jws<Claims> claimsJws = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);  // 解析并验证签名return true;} catch (Exception e) {return false;  // 验证失败}
    }
    

七、总结

  • JWT 用于用户认证和授权,包含三部分:头部、负载和签名。
  • 登录流程:通过验证用户名、密码和验证码,生成 JWT Token,并通过 Redis 存储用户的 token
  • Token 校验:通过 jwtUtil.checkToken 方法验证客户端提供的 token 是否有效。
  • 安全性:JWT 通过密钥加密生成和验证签名,确保信息传输的安全性。

JWT 的优势在于无状态认证、跨域认证、以及扩展性强,但也需要注意密钥管理、过期时间控制等安全细节。
在这里插入图片描述


http://www.ppmy.cn/server/164407.html

相关文章

kamailio-ACC_RADIUS模块详解,附加AAA协议

AAA 协议详解 AAA 是 Authentication&#xff08;认证&#xff09;、Authorization&#xff08;授权&#xff09; 和 Accounting&#xff08;计费&#xff09; 的缩写&#xff0c;是网络管理中用于控制用户访问资源的核心框架。AAA 协议的主要目的是确保只有合法用户可以访问网…

MapReduce简单应用(一)——WordCount

目录 1. 执行过程1.1 分割1.2 Map1.3 Combine1.4 Reduce 2. 代码和结果2.1 pom.xml中依赖配置2.2 工具类util2.3 WordCount2.4 结果 参考 1. 执行过程 假设WordCount的两个输入文本text1.txt和text2.txt如下。 Hello World Bye WorldHello Hadoop Bye Hadoop1.1 分割 将每个文…

面试问题知识

文章目录 1. Linux 和 CentOS基础指令&#xff1a;VMware 和 CentOS&#xff1a;扩充问题&#xff1a; 2. 前端开发&#xff08;JS、CSS&#xff09;JavaScript&#xff1a;CSS&#xff1a;扩充问题&#xff1a; 3. 数据库&#xff08;MySQL&#xff09;基础语法&#xff1a;事…

Go学习:类型转换需注意的点 以及 类型别名

目录 1. 类型转换 2. 类型别名 1. 类型转换 在从前的学习中&#xff0c;知道布尔bool类型变量只有两种值true或false&#xff0c;C/C、Python、JAVA等编程语言中&#xff0c;如果将布尔类型bool变量转换为整型int变量&#xff0c;通常采用 “0为假&#xff0c;非0为真”的方…

代理模式 - 代理模式的应用

引言 代理模式&#xff08;Proxy Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许你提供一个代理对象来控制对另一个对象的访问。代理对象通常会在客户端和目标对象之间起到中介的作用&#xff0c;从而可以在不改变目标对象的情况下&#xff0c;增加额外的功能或控…

MySQL知识点总结(十七)

在从属服务器上执行RESET SLAVE命令时&#xff0c;会发生哪些操作&#xff1f; RESET SLAVE命令会断开从属服务器与主服务器的连接&#xff0c;以重置从属服务器&#xff0c;具体效果如下&#xff1a;清除 master.info和relay.log资料档案库删除所有中继日志启动新的中继日志文…

基于FPGA的BT656编解码

概述 BT656全称为“ITU-R BT.656-4”或简称“BT656”,是一种用于数字视频传输的接口标准。它规定了数字视频信号的编码方式、传输格式以及接口电气特性。在物理层面上,BT656接口通常包含10根线(在某些应用中可能略有不同,但标准配置为10根)。这些线分别用于传输视频数据、…

LLaMA-Factory 微调LLaMA3

LoRA介绍 LoRA&#xff08;Low-Rank Adaptation&#xff09;是一种用于大模型微调的技术&#xff0c; 通过引入低秩矩阵来减少微调时的参数量。在预训练的模型中&#xff0c; LoRA通过添加两个小矩阵B和A来近似原始的大矩阵ΔW&#xff0c;从而减 少需要更新的参数数量。具体来…