JWT解码报错:Illegal base64url character: ' ' 问题求助
问题:JWT解码触发"Illegal base64url character: ' '"错误,无法提取Claims信息
登录生成JWT Token后,在其他服务验证用户身份时,解码Token提取用户信息并匹配数据库时触发错误:Illegal base64url character: ' ',且执行System.out.println(claims)无输出。
相关代码
package com.example.RentCar.Services; import java.security.Key; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.function.Function; import com.example.RentCar.DTOS.UserRequestDTO; import com.example.RentCar.Models.User; import com.example.RentCar.Repository.UserRepository; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Service; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.io.Decoders; import io.jsonwebtoken.security.Keys; @Service public class JwtServicesImpl implements JwtServices { private UserRequestDTO userRequestDTO; //private final UserRepository userRepository; // @Value("${token.signing.key}") private String jwtSigningKey = "413F4428472B4B6250655368566D5970337336763979244226452948404D6351"; @Override public String extractUserName(String token) { return extractClaim(token, Claims::getSubject); } @Override public String generateToken(User user) { return generateToken(new HashMap<>(), user); } @Override public boolean isTokenValid(String token, UserServicesImpl userServices) { final String email = extractUserName(token); UserDetails user = (userServices.loadUserByUsername(email)); String email2 = user.getUsername(); return (email.equals(email2) && !isTokenExpired(token)); } private <T> T extractClaim(String token, Function<Claims, T> claimsResolvers) { final Claims claims = extractAllClaims(token); System.out.println(claims); //not printing return claimsResolvers.apply(claims); } private String generateToken(Map<String, Object> extraClaims, User user) { return Jwts.builder().setClaims(extraClaims).setSubject(user.getUserEmail()) .setIssuedAt(new Date(System.currentTimeMillis())) .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 24)) .signWith(getSigningKey(), SignatureAlgorithm.HS256).compact(); } private boolean isTokenExpired(String token) { return extractExpiration(token).before(new Date()); } private Date extractExpiration(String token) { return extractClaim(token, Claims::getExpiration); } private Claims extractAllClaims(String token) { return Jwts.parserBuilder().setSigningKey(getSigningKey()).build().parseClaimsJws(token) .getBody(); } private Key getSigningKey() { // System.out.println(jwtSigningKey); byte[] keyBytes = Decoders.BASE64.decode(jwtSigningKey); return Keys.hmacShaKeyFor(keyBytes); } }
错误栈
io.jsonwebtoken.io.DecodingException: Illegal base64url character: ' ' at io.jsonwebtoken.io.Base64.ctoi(Base64.java:221) at io.jsonwebtoken.io.Base64.decodeFast(Base64.java:270) at io.jsonwebtoken.io.Base64Decoder.decode(Base64Decoder.java:36) at io.jsonwebtoken.io.Base64Decoder.decode(Base64Decoder.java:23) at io.jsonwebtoken.io.ExceptionPropagatingDecoder.decode(ExceptionPropagatingDecoder.java:36) at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:288) at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:529) at io.jsonwebtoken.impl.DefaultJwtParser.parseClaimsJws(DefaultJwtParser.java:589) at io.jsonwebtoken.impl.ImmutableJwtParser.parseClaimsJws(ImmutableJwtParser.java:173) at com.example.RentCar.Services.JwtServicesImpl.extractAllClaims(JwtServicesImpl.java:76) at com.example.RentCar.Services.JwtServicesImpl.extractClaim(JwtServicesImpl.java:55) at com.example.RentCar.Services.JwtServicesImpl.extractUserName(JwtServicesImpl.java:34) at com.example.RentCar.Controllers.UserController.ModifyAddress(UserController.java:36) at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) at java.base/java.lang.reflect.Method.invoke(Method.java:578) at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1081) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:974) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1011)
解决方案
1. 清理Token中的空格字符
错误根源是传入的Token包含空格,直接导致Base64解码失败。修改extractAllClaims方法,先移除Token中的所有空格:
private Claims extractAllClaims(String token) { // 移除Token中的所有空格字符 String cleanToken = token.replaceAll("\\s+", ""); return Jwts.parserBuilder().setSigningKey(getSigningKey()).build().parseClaimsJws(cleanToken) .getBody(); }
2. 规范Token的获取逻辑
如果Token是从HTTP请求的Authorization头获取,注意标准格式是Bearer <token>,需要先截取Bearer 前缀后的内容,再清理空格:
// 在Controller或过滤器中处理Token String authHeader = request.getHeader("Authorization"); if (authHeader != null && authHeader.startsWith("Bearer ")) { // 截取前缀并清理空格 String token = authHeader.substring(7).replaceAll("\\s+", ""); // 传入JwtServices进行验证 }
3. 修复签名密钥的解码方式
你的签名密钥413F4428472B4B6250655368566D5970337336763979244226452948404D6351是十六进制字符串,但当前代码用Decoders.BASE64.decode解码,这是错误的,应该改用十六进制解码:
private Key getSigningKey() { // 十六进制字符串转字节数组 byte[] keyBytes = Decoders.HEX.decode(jwtSigningKey); return Keys.hmacShaKeyFor(keyBytes); }
注:错误的解码方式会导致签名验证失败,即使解决了空格问题,后续仍可能出现Token无效的情况。
4. 验证生成的Token格式
可以在generateToken方法中打印生成的Token,确认没有包含空格或异常字符:
private String generateToken(Map<String, Object> extraClaims, User user) { String token = Jwts.builder().setClaims(extraClaims).setSubject(user.getUserEmail()) .setIssuedAt(new Date(System.currentTimeMillis())) .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 24)) .signWith(getSigningKey(), SignatureAlgorithm.HS256).compact(); // 打印生成的Token,检查格式是否正常 System.out.println("Generated Token: " + token); return token; }
内容的提问来源于stack exchange,提问作者Max
相关产品推荐
相关产品推荐

