JWT概念

概述

JWT(JSON Web Token)是一种基于JSON在客户端和服务器之间传递声明的令牌格式。它最常见的用途是保存登录态,让客户端在后续请求中证明自己是谁。

在前后端分离、App、小程序、纯API服务里,JWT很常见。用户登录成功以后,服务端签发JWT,客户端保存JWT,后续请求把JWT放到HTTP Header中。

Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...

服务端收到请求后,只要校验签名和过期时间,就能判断这段Token是否可信。

结构

JWT由三段组成,中间用.分隔。

Header.Payload.Signature

Header描述令牌类型和签名算法:

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

Payload保存声明,也就是业务需要传递的信息:

{
  "sub": "10001",
  "username": "zhouzhou",
  "role": "USER",
  "iat": 1710000000,
  "exp": 1710003600
}

Signature是签名,用来证明Header和Payload没有被篡改。只要服务端密钥没有泄露,别人就不能伪造一个合法Token。

常见声明

JWT里有一些标准字段,项目里经常会用到:

字段 含义 说明
sub Subject 用户主体,一般放用户ID
iat Issued At 签发时间
exp Expiration Time 过期时间
iss Issuer 签发方
aud Audience 接收方
jti JWT ID Token唯一ID

我一般会把用户ID放到sub,把用户名、租户ID、权限版本作为自定义字段。权限列表要不要放进去,要看项目对权限实时性的要求。

优点

  • 天生适合WEB和HTTP Header。
  • 不依赖Session,服务端可以保持无状态。
  • 使用方便,各个平台都有成熟类库。
  • 可以和权限、租户、刷新Token等策略组合使用。
  • 适合前后端分离、App、小程序、纯API服务。

无状态是JWT最吸引人的地方。服务端不需要保存每个用户的Session,应用扩容时会简单很多。

缺点

JWT也有自己的代价。它签发出去以后,在过期之前通常都会有效。用户退出登录、管理员封禁账号、用户修改密码以后,如果没有额外机制,旧Token可能仍然能访问接口。

常见解决方式有三种:

  • Access Token设置较短有效期。
  • 使用Refresh Token刷新登录态。
  • 在Token里加入版本号,服务端校验当前版本。

另外,JWT默认只是Base64Url编码加签名,不是加密。任何人拿到JWT都能解码出Payload,所以不要在里面放密码、手机号、身份证、微信session_key等敏感信息。

签名算法

常见签名算法分两类。

HMAC使用同一个密钥签发和校验,典型算法是HS256。它实现简单,适合自己的服务端签发、自己的服务端校验。

RSA或ECDSA使用私钥签发、公钥校验,典型算法是RS256。它适合多个服务共同校验Token的场景,因为校验方只需要拿公钥,不需要拿私钥。

如果是单体或普通前后端分离项目,HS256通常够用。如果是微服务或开放平台,RS256会更容易管理密钥边界。

Java中创建JWT

下面示例使用jjwt,只展示核心思路。

public String createToken(Long userId, String username, SecretKey secretKey) {
    Instant now = Instant.now();

    return Jwts.builder()
            .subject(userId.toString())
            .claim("username", username)
            .issuedAt(Date.from(now))
            .expiration(Date.from(now.plus(Duration.ofHours(1))))
            .signWith(secretKey)
            .compact();
}

这里的subject就是用户ID,expiration是过期时间。过期时间一定要设置,不要签发永不过期的Token。

解析时反过来:

public Claims parseToken(String token, SecretKey secretKey) {
    return Jwts.parser()
            .verifyWith(secretKey)
            .build()
            .parseSignedClaims(token)
            .getPayload();
}

如果签名不正确、Token过期、格式错误,解析过程会抛出异常。业务代码不要忽略这些异常,应该统一返回401。

保存位置

浏览器项目里,JWT可以放在内存、sessionStoragelocalStorage或Cookie里。每种方式都有取舍。

位置 优点 问题
内存 泄露面小 页面刷新后丢失
sessionStorage 当前标签页可用 XSS后可能被读取
localStorage 使用方便 XSS后可能被读取
Cookie 浏览器自动携带 要处理CSRF和SameSite

如果是小程序或App,一般会使用平台提供的本地存储能力。无论放在哪里,都要控制Token有效期,并且不要把Refresh Token暴露在不可信环境里太久。

使用建议

JWT适合用来传递“已经认证过的身份”,不适合保存大量业务数据。Token越小越好,字段越稳定越好。

我一般会这样设计:

  • Access Token有效期短一些。
  • Payload里只放用户ID、租户ID、权限版本等必要字段。
  • 权限变化要求实时生效时,从缓存或数据库加载权限。
  • 修改密码、封禁账号时递增Token版本号。
  • 敏感信息只放在服务端,不放进JWT。

把JWT理解成一张临时通行证会比较准确。它能证明用户身份,但不应该替代完整的用户和权限系统。

© 舟哥 all right reserved,powered by Gitbook文件修订时间: 2026-07-16 12:52:26
作者: 舟哥
链接:https://www.b919p4.com
来源: B919P4
本文原创发布于B919P4,©著作权归作者所有,转载请注明出处,谢谢合作!

undefined

results matching ""

    No results matching ""