首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >JWT令牌详解

JWT令牌详解

原创
作者头像
艾伦耶格尔
发布2025-08-14 17:58:17
发布2025-08-14 17:58:17
2.3K0
举报
文章被收录于专栏:Java后端Java后端

在现代 Web 应用和微服务架构中,用户身份认证是系统安全的第一道防线。传统的 Session 认证在分布式系统中面临共享难题,而 JWT(JSON Web Token) 凭借其无状态、自包含、跨域友好的特性,成为当前最主流的身份认证方案之一。

本文将带你深入理解 JWT 的核心原理,并通过 Spring Boot 3.x + JJWT 实现令牌的生成、解析、验证与实际应用


一、什么是 JWT?自包含的身份令牌

JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在各方之间以 JSON 对象的形式安全地传输信息。它通常用于:

  • 用户身份认证(Authentication)
  • 信息交换(Information Exchange)
  • 单点登录(SSO)
  • API 接口鉴权

✅ JWT 的核心优势:

  • 无状态(Stateless):服务端无需存储会话信息
  • 自包含(Self-contained):所有用户信息都包含在令牌中
  • 跨域支持:天然支持前后端分离、微服务架构
  • 可扩展性好:支持自定义声明(Claims)

二、JWT 的结构:三段式编码

一个 JWT 令牌由三部分组成,用 . 分隔:

代码语言:javascript
复制
xxxxx.yyyyy.zzzzz

1. Header(头部)

包含令牌类型和签名算法:

代码语言:json
复制
{
  "alg": "HS256",
  "typ": "JWT"
}
  • alg:签名算法,如 HS256(HMAC SHA-256)、RS256(RSA)
  • typ:令牌类型,固定为 JWT

编码后:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9


2. Payload(负载)

包含“声明(Claims)”——关于用户和附加信息的 JSON 数据。

声明类型:

类型

说明

示例

Registered Claims

预定义标准字段(非强制)

exp(过期时间)、iss(发行人)、sub(主题)、aud(受众)

Public Claims

公共字段,建议使用命名空间

https://example.com/role

Private Claims

自定义私有字段

userId, username, role

示例:

代码语言:json
复制
{
  "id": 1,
  "username": "KBL",
  "exp": 1727779154,
  "iss": "myapp"
}

编码后:eyJpZCI6MSwidXNlcm5hbWUiOiJLQkwiLCJleHAiOjE3Mjc3NzkxNTR9

⚠️ 注意:

  • 不要在 Payload 中存放敏感信息(如密码),因为 Base64 可解码
  • 所有信息都会暴露给客户端,仅用于传输非敏感身份数据

3. Signature(签名)

用于验证令牌完整性防止篡改

生成方式:

代码语言:java
复制
HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  secretKey
)

签名后:7Nt1IbfAZ52PKW5cjjbjr3oND9iaJxvGFO5w5g3uNV8


完整 JWT 示例

代码语言:javascript
复制
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJpZCI6MSwidXNlcm5hbWUiOiJLQkwiLCJleHAiOjE3Mjc3NzkxNTR9.
7Nt1IbfAZ52PKW5cjjbjr3oND9iaJxvGFO5w5g3uNV8

三、JWT 的工作流程

jwt工作流程
jwt工作流程

四、环境准备

环境

版本

操作系统

Windows 10

IDE

IntelliJ IDEA

JDK

17

构建工具

Maven 3.6.0+

Spring Boot

3.x

JWT 库

JJWT 0.12.3

✅ 全程需联网下载依赖。


五、Spring Boot 中集成 JWT

5.1 引入 JJWT 依赖

pom.xml 中添加:

代码语言:xml
复制
<!-- JWT 依赖 -->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.12.3</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.12.3</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.12.3</version>
    <scope>runtime</scope>
</dependency>

💡 注意:JJWT 0.12+ 版本已模块化,需引入 apiimpljackson 三个模块。


5.2 生成 JWT 令牌(Java 代码)

代码语言:java
复制
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.junit.jupiter.api.Test;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class JwtTest {

    // 密钥(应配置在 application.yml 中,此处仅为演示)
    private static final String SECRET_KEY = "chengxuyuanchengxuyuanchengxuyuanchengxuyuanchengxuyuan";

    /**
     * 生成 JWT 令牌
     */
    @Test
    public void generateJwt() {
        // 自定义负载(Claims)
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", 1);
        claims.put("username", "KBL");

        // 生成令牌
        String jwt = Jwts.builder()
                .setClaims(claims)  // 设置自定义内容
                .setExpiration(new Date(System.currentTimeMillis() + 24 * 3600 * 1000)) // 24小时有效期
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY) // 使用 HS256 算法签名
                .compact();

        System.out.println("生成的 JWT 令牌:");
        System.out.println(jwt);
    }
}

✅ 输出示例: eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwidXNlcm5hbWUiOiJLQkwiLCJleHAiOjE3Mjc3NzkxNTR9.7Nt1IbfAZ52PKW5cjjbjr3oND9iaJxvGFO5w5g3uNV8


5.3 解析 JWT 令牌

方式一:Java 代码解析(推荐)
代码语言:java
复制
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import org.junit.jupiter.api.Test;

public class JwtTest {

    private static final String SECRET_KEY = "chengxuyuanchengxuyuanchengxuyuanchengxuyuanchengxuyuan";

    /**
     * 解析 JWT 令牌
     */
    @Test
    public void parseJwt() {
        String jwt = "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwidXNlcm5hbWUiOiJLQkwiLCJleHAiOjE3Mjc3NzkxNTR9.7Nt1IbfAZ52PKW5cjjbjr3oND9iaJxvGFO5w5g3uNV8";

        try {
            Claims claims = Jwts.parser()
                    .setSigningKey(SECRET_KEY) // 必须与生成时密钥一致
                    .build()
                    .parseClaimsJws(jwt) // 解析并验证签名
                    .getBody();

            System.out.println("解析成功,Claims 内容:");
            System.out.println("用户ID: " + claims.get("id"));
            System.out.println("用户名: " + claims.get("username"));
            System.out.println("过期时间: " + claims.getExpiration());

        } catch (Exception e) {
            System.err.println("JWT 解析失败:" + e.getMessage());
            // 可能原因:签名无效、令牌过期、密钥错误
        }
    }
}

⚠️ 异常处理非常重要!常见异常:

  • ExpiredJwtException:令牌已过期
  • SignatureException:签名不匹配(可能被篡改)
  • MalformedJwtException:格式错误

方式二:在线解析(调试用)
  1. 打开 https://jwt.io
  2. 在左侧输入你的 JWT 令牌
  3. VERIFY SIGNATURE 区域输入密钥(SECRET_KEY
  4. 右侧将自动显示解码后的 Header、Payload 和签名验证状态

✅ 适用于调试、教学、快速验证。


六、JWT 使用注意事项与最佳实践

✅ 正确做法

项目

建议

密钥管理

使用强密钥(至少 32 字符),不要硬编码,应配置在 application.yml 或环境变量中

传输安全

必须使用 HTTPS 传输 JWT,防止中间人攻击

存储位置

前端推荐使用 HttpOnly Cookie 存储,避免 XSS 攻击;若用 localStorage,需防范 XSS

过期时间

设置合理过期时间(如 2h),配合 Refresh Token 实现自动续期

敏感信息

不要在 JWT 中存放密码、手机号等敏感信息


❌ 避免的坑

  • ❌ 使用弱密钥(如 123456
  • ❌ 在 URL 中传递 JWT(易被日志记录)
  • ❌ 无限期有效令牌
  • ❌ 不验证签名就使用 payload 数据
  • ❌ 用 JWT 做 Session 存储(违背无状态原则)

七、JWT 在 Spring Boot 项目中的实际应用

在真实项目中,JWT 通常结合 拦截器(Interceptor)过滤器(Filter) 使用:

代码语言:java
复制
@Component
public class JwtAuthInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String token = request.getHeader("Authorization");
        if (token != null && token.startsWith("Bearer ")) {
            String jwt = token.substring(7);
            try {
                Claims claims = Jwts.parser().setSigningKey(SECRET_KEY).build().parseClaimsJws(jwt).getBody();
                // 将用户信息存入 ThreadLocal 或 SecurityContext
                return true;
            } catch (Exception e) {
                response.setStatus(401);
                return false;
            }
        }
        response.setStatus(401);
        return false;
    }
}

🚀 进阶建议:结合 Spring Security 实现完整的认证授权体系。


八、JWT 的局限性

问题

解决方案

无法主动失效(除非过期)

使用 黑名单机制(Redis 存储已注销的 JWT)

令牌较大

避免存放过多自定义字段

一旦泄露风险高

缩短有效期,使用 Refresh Token


结语

JWT 是现代 Web 开发中不可或缺的身份认证技术。它简单、高效、跨平台,特别适合前后端分离微服务架构

但记住:JWT 不是银弹。它解决了 Session 共享问题,也带来了令牌管理、安全防护等新挑战。

掌握 JWT 的核心原理与安全实践,是每一位 Java 开发者迈向高阶的必经之路。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、什么是 JWT?自包含的身份令牌
  • 二、JWT 的结构:三段式编码
    • 1. Header(头部)
    • 2. Payload(负载)
      • 声明类型:
    • 3. Signature(签名)
    • 完整 JWT 示例
  • 三、JWT 的工作流程
  • 四、环境准备
  • 五、Spring Boot 中集成 JWT
    • 5.1 引入 JJWT 依赖
    • 5.2 生成 JWT 令牌(Java 代码)
    • 5.3 解析 JWT 令牌
      • 方式一:Java 代码解析(推荐)
      • 方式二:在线解析(调试用)
  • 六、JWT 使用注意事项与最佳实践
    • ✅ 正确做法
    • ❌ 避免的坑
  • 七、JWT 在 Spring Boot 项目中的实际应用
  • 八、JWT 的局限性
  • 结语
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档