目录- 一、先理解JWT的标准结构
- 二、错误的常见原因(按优先级排查)
- 1. 传入的令牌为空/空白字符串
- 2. 令牌被截断/拼接错误
- 3. 令牌格式错误(非JWT)
- 4. 令牌被篡改/手动修改
- 三、通用解决方案(解析前增加校验)
- 四、额外注意点
- 快速定位技巧
这个错误的核心是:你传入的JWT令牌字符串没有包含必需的2个英文句点(.),导致JWT解析器无法按标准拆分令牌结构。
一、先理解JWT的标准结构
合法的JWT令牌必须是 Header.Payload.Signature 三段式结构(包含2个句点),例如:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
- 第一段:Header(Base64编码)
- 第二段:Payload(Base64编码)
- 第三段:Signature(签名)
- 段与段之间用英文句点
. 分隔
二、错误的常见原因(按优先级排查)
1. 传入的令牌为空/空白字符串
- 现象:前端未传递token、后端接收时为空,或token被误置为空字符串(
"")。 - 排查:
// 解析前先校验token是否为空
String token = request.getHeader("Authorization");
if (token == null || token.trim().isEmpty()) {
throw new IllegalArgumentException("JWT令牌不能为空");
}
// 若用Bearer Token,需先截取(例如:Bearer <token>)
if (token.startsWith("Bearer ")) {
token = token.substring(7).trim(); // 去掉"Bearer "前缀
}
2. 令牌被截断/拼接错误
- 现象:token传递过程中被截断(如URL编码/解码错误、字符长度限制),或拼接时丢失句点。
- 排查:
- 打印原始token值,确认是否完整(例如:
System.out.println("原始token:" + token)); - 检查前端传递时是否对token做了不必要的转义(如把
. 转成 %2E 但后端未解码)。
3. 令牌格式错误(非JWT)
- 现象:传入的不是JWT令牌,而是普通字符串、SessionID、其他格式的token(如只有一段/一段半)。
- 排查:
- 确认生成token的代码是否正确(例如:使用JJWT/Java JWT库生成时,是否完整调用了签名步骤);
- 示例:正确生成JWT(以JJWT为例):
// 正确生成三段式JWT
String jwt = Jwts.builder()
.setHeaderParam("alg", "HS256")
.setSubject("user123")
.signWith(SignatureAlgorithm.HS256, "secretKey")
.compact(); // compact()会生成标准的Header.Payload.Signature结构
4. 令牌被篡改/手动修改
- 现象:token被人为删除句点,或传输中被篡改(如空格替换句点)。
- 排查:校验token的字符组成,确保仅包含Base64URL合法字符(字母、数字、
-、_、.)。
三、通用解决方案(解析前增加校验)
在解析JWT前,先校验token的格式合法性,避免直接抛出异常:
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
public String parseJwt(String token) {
// 第一步:校验非空+句点数量
if (token == null || token.trim().isEmpty()) {
throw new IllegalArgumentException("JWT令牌不能为空");
}
int dotCount = token.length() - token.replace(".", "").length();
if (dotCount != 2) {
throw new IllegalArgumentException("JWT令牌格式错误,必须包含2个句点(.),当前数量:" + dotCount);
}
// 第二步:解析JWT(示例)
try {
return Jwts.parser()
.setSigningKey("secretKey")
.parseClaimsJws(token)
.getBody()
.getSubject();
} catch (JwtException e) {
throw new RuntimeException("JWT解析失败:" + e.getMessage());
}
}
四、额外注意点
- Bearer Token前缀:前端传递的token常带
Bearer 前缀(如 Bearer eyJhbGciOiJIUzI1Ni...),需先截取掉前缀再解析; - Base64URL编码:JWT的段使用Base64URL编码(区别于普通Base64),若手动解码需注意替换字符(
+→-,/→_,去掉末尾=); - 框架自动解析:若使用Spring Security OAuth2等框架,需确认配置的token提取器是否正确(如从Header/参数中提取)。
快速定位技巧
在解析代码前添加日志,打印原始token值:
System.out.println("待解析的JWT令牌:[" + token + "]");
通过日志可直接判断:
- 若打印
[] → token为空; - 若打印
[eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9] → 只有一段(缺少2个句点); - 若打印
[eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkw] → 只有1个句点(缺少1个)。
到此这篇关于Java出现:JWT strings must contain exactly 2 period characters. Found: 0的常见原因及解决方案的文章就介绍到这了,更多相关Java出现:characters. Found: 0内容请搜索琼殿技术社区以前的文章或继续浏览下面的相关文章希望大家以后多多支持琼殿技术社区!
您可能感兴趣的文章:- Java17和springboot3.0使用shiro报ClassNotFoundException的解决
- Java日期接收报错:could not be parsed, unparsed text found at index 10解决办法
- Android Studio 升级到3.0 提示 java.lang.NoClassDefFoundError的解决方法
- EJB3.0部署消息驱动Bean抛javax.naming.NameNotFoundException异常
|