如何在 Java 中从苹果公钥 JSON 响应中获取公钥?



我们正在尝试在我们的iOS应用程序中添加"使用Apple登录"。当客户端工作正常时,我们的后端是用Java编写的,我们无法解码Apple的公钥。当您点击 URL https://appleid.apple.com/auth/keys 时,它会为您提供公钥。但是当我尝试使PublicKey对象是Java时,它无法识别n并从那里e值。这些 Base64 是否编码?

当我尝试解码 Base64 中的ne值时,它给了我illegal character 2d.我怀疑它是 base64 的原因是在一个 NodeJS 包 (https://www.npmjs.com/package/node-rsa( 中,他们正在通过 base64 解码 n 和 e 值。但问题是指数值(e(是AQAB,它永远不可能是base64。如何从中创建公钥对象?

我使用的代码是:

HttpResponse<String> responsePublicKeyApple =  Unirest.get("https://appleid.apple.com/auth/keys").asString();
ApplePublicKeyResponse applePublicKeyResponse = new Gson().fromJson(responsePublicKeyApple.getBody(),ApplePublicKeyResponse.class);
System.out.println("N: "+applePublicKeyResponse.getKeys().get(0).getN());
System.out.println("E: "+applePublicKeyResponse.getKeys().get(0).getE());
byte[] decodedBytesE = Base64.getDecoder().decode(applePublicKeyResponse.getKeys().get(0).getE());
String decodedE = new String(decodedBytesE);
System.out.println("decode E: "+decodedE);
byte[] decodedBytesN = Base64.getDecoder().decode(applePublicKeyResponse.getKeys().get(0).getN());
String decodedN = new String(decodedBytesN);
System.out.println("decode N: "+decodedN);
BigInteger bigIntegerN = new BigInteger(decodedN,16);
BigInteger bigIntegerE = new BigInteger(decodedE,16);
RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(bigIntegerN,bigIntegerE);
KeyFactory keyFactory = KeyFactory.getInstance(SignatureAlgorithm.RS256.getValue());
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);

它无法解码部分ne值。另一件事是苹果的回应是说他们使用RS256算法来签署令牌,但是当我尝试这样做时

KeyFactory keyFactory = KeyFactory.getInstance(SignatureAlgorithm.RS256.getValue());

它说RS256 keyfactory is not available.

我该如何解决这两个问题?请帮忙。

实际上,这些NE值是使用base64url编码的,如RFC7518中所述。此代码将向您展示如何执行您的请求。我使用杰克逊来读取您提供的 JSON:

String json = Files.lines(Paths.get("src/main/resources/test.json")).collect(Collectors.joining());
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// here is the parsing of PublicKey
ApplePublicKeyResponse applePublicKeyResponse = objectMapper.readValue(json, ApplePublicKeyResponse.class);

Key key = applePublicKeyResponse.getKeys().get(0);
byte[] nBytes = Base64.getUrlDecoder().decode(key.getN());
byte[] eBytes = Base64.getUrlDecoder().decode(key.getE());
BigInteger n = new BigInteger(1, nBytes);
BigInteger e = new BigInteger(1, eBytes);
RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(n,e);
KeyFactory keyFactory = KeyFactory.getInstance(key.getKty()); //kty will be "RSA"
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);

另外如前所述,key.getKty()将返回"RSA"。因此,当您要解析 RSA 密钥并且RS256是使用 RSA 和 SHA-256 哈希的签名算法的名称时,您应该将此值传递给KeyFactory.getInstance

我使用了接受符号和原始字节的BigInteger构造函数。符号设置为 1 以获得正值。

最新更新