You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

不使用NimbusDS库实现Java JWT签名遇错误求助

问题:Java原生库实现JWT客户端断言生成失败排查

原NimbusDS实现代码

public static String getClientJwtAssertion(String secureKey, PrivateKey privateKey) {
    try {
        Date now = new Date();
        SignedJWT signedJWT = new SignedJWT((new JWSHeader.Builder(JWSAlgorithm.RS256)).keyID(getThumbprint(secureKey)).build(),
                (new com.nimbusds.jwt.JWTClaimsSet.Builder())
                        .jwtID(UUID.randomUUID().toString())
                        .subject(Constants.CLIENT_ID)
                        .issuer(Constants.CLIENT_ID)
                        .issueTime(new Date())
                        .expirationTime(new Date(now.getTime() + Constants.EXPIRES_IN))
                        .build());
        Set<JWSSignerOption> options = Collections.singleton(AllowWeakRSAKey.getInstance());
        JWSSigner rsaSigner = new RSASSASigner(privateKey, options);
        signedJWT.sign(rsaSigner);
        return signedJWT.serialize();
    } catch (Exception e) {
        return null;
    }
}

自行编写的Java原生实现代码

public static String signJWTToken(Certificate certificate, PrivateKey privateKey) {
    String header = "{\"alg\":\"RS256\"}";
    String claimTemplate =  "'{'\"jti\": \"{0}\", \"sub\": \"{1}\", \"aud\": \"{2}\", \"iss\": \"{3}\", \"iat\": \"{4}\", \"exp\": \"{5}\"'}'";
    StringBuilder token = new StringBuilder();
    try {
       token.append(Base64.encodeBase64URLSafeString(header.getBytes(StandardCharsets.UTF_8)));
       token.append(".");

       Date now = new Date();
       String[] claimArray = new String[6];
       claimArray[0] = UUID.randomUUID().toString();
       claimArray[1] = Constants.CLIENT_ID;
       claimArray[2] = Constants.ACCESS_TOKEN_URI;
       claimArray[3] = Constants.CLIENT_ID;
       claimArray[4] = Long.toString(now.getTime());
       claimArray[5] = Long.toString(now.getTime() + Constants.EXPIRES_IN);

        MessageFormat claims= new MessageFormat(claimTemplate);
        // create payload and add to token
        String payload = claims.format(claimArray);
        token.append(Base64.encodeBase64URLSafeString(payload.getBytes(StandardCharsets.UTF_8)));

        // Sign JWT header
        Signature signature = Signature.getInstance("AllowWeakRSAKey");
        signature.initSign(privateKey);
        signature.update(token.toString().getBytes(StandardCharsets.UTF_8));
        String signedPayload = Base64.encodeBase64URLSafeString((signature.sign()));

        token.append(".");
        token.append(signedPayload);

    } catch (Exception e) {
        new Throw Exception(e);
    }
    return token.toString();
}

出现的错误信息

加密块大小异常

Caused by: javax.crypto.IllegalBlockSizeException: Data must not be longer than 245 bytes
at java.base/com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:349)
at java.base/com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:406)
at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2088)
at java.base/java.security.Signature$CipherAdapter.engineSign(Signature.java:1529)
... 4 common frames omitted

服务器认证错误

23:36:59.867 ERROR TokenApplication - Error retrieving access token
org.springframework.web.client.HttpClientErrorException$BadRequest: 400 Bad Request: "{\"error\":\"invalid_client\",\"error_description\":\"MSIS9622: Client authentication failed. Please verify the credential provided for client authentication is valid.\"}"
at org.springframework.web.client.HttpClientErrorException.create(HttpClientErrorException.java:101)

排查思路

  • 签名算法完全错误:Signature.getInstance("AllowWeakRSAKey")是无效的算法名,RS256对应的标准签名算法应为"SHA256withRSA"。错误的算法会导致底层加密逻辑混乱,直接触发块大小异常。
  • JWT声明字段不匹配:原代码没有aud字段,自行编写的代码新增了该字段并赋值为Constants.ACCESS_TOKEN_URI,需确认服务端是否要求该字段,或是否与原实现的断言结构一致,多余或不匹配的字段会导致认证失败。
  • 时间戳格式错误:JWT的iat和exp要求是UNIX时间戳(秒级),但代码中使用了now.getTime()(毫秒级),会导致时间戳数值过大,服务端会判定断言过期或无效,需改为now.getTime() / 1000。
  • Payload生成语法错误:claimTemplate中的'{'和'}'多余,会导致生成的JSON格式错误(出现单引号包裹大括号),正确模板应为"{\"jti\": \"{0}\", \"sub\": \"{1}\", \"aud\": \"{2}\", \"iss\": \"{3}\", \"iat\": \"{4}\", \"exp\": \"{5}\"}",JSON格式错误会让服务端无法解析断言。
  • Base64编码合规性检查:需确认Base64.encodeBase64URLSafeString是否符合JWT标准的Base64URL编码要求(自动去除填充字符=),编码不符合标准会导致服务端无法正确解码断言内容。
  • 弱密钥处理缺失:原代码设置了AllowWeakRSAKey选项,若使用的RSA密钥长度过短(如小于2048位),原生Signature默认会拒绝,需检查密钥长度;若必须使用弱密钥,需调整JVM安全策略或更换合规密钥。
  • 异常处理语法错误:代码中new Throw Exception(e)是无效语法,应改为throw new RuntimeException(e),否则异常被静默处理,无法定位中间环节的问题。

内容的提问来源于stack exchange,提问作者user583726

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 22:15:53