首页 > 解决方案 > AppleId 授权码的 Java 验证

问题描述

我有用 Java 实现的 AppleId 授权代码。移动应用程序获取授权码并将其转发到后端。授权代码令牌如下所示:

c648564b27ce0a86cdb090de49cf4a25f.0.zrnvw.ZJ1I65-gU_xBRXAmLI06dv
(it's randomized)

好的,现在,我的验证 bean 看起来像这样:

@Component
public class AppleIdTokenFactory {

    private final String audience = "https://appleid.apple.com";
    private final Integer expirationInMs = 1000 * 60 * 5;

    private PKCS8Key readPrivateKey(String appleIdCertificateResourcePath) throws Exception {
        InputStream inStream = this.getClass().getClassLoader().getResourceAsStream(appleIdCertificateResourcePath);
        InputStreamReader inStreamReader = new InputStreamReader(inStream, "UTF-8");
        BufferedReader reader = new BufferedReader(inStreamReader);
        String certificateFileContent =  reader.lines().collect(Collectors.joining());

        String privateKeyPEM = certificateFileContent
                .replace("-----BEGIN PRIVATE KEY-----", "")
                .replaceAll(System.lineSeparator(), "")
                .replace("-----END PRIVATE KEY-----", "");

        byte[] encoded = Base64.getDecoder().decode(privateKeyPEM);

        KeyFactory keyFactory = KeyFactory.getInstance("EC");
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
        return (PKCS8Key) keyFactory.generatePrivate(keySpec);
    }

    public String createAppleIdTokenAsString(String appleIdCertificateResourcePath, String appleKeyId, String appleTeamId, String appleClientId) throws Exception {
        PrivateKey pKey = readPrivateKey(appleIdCertificateResourcePath);
        Date issuedAt = new Date(System.currentTimeMillis());
        Date expiresAt = new Date(System.currentTimeMillis() + expirationInMs);

        return Jwts.builder()
                .setHeaderParam(JwsHeader.KEY_ID, appleKeyId)
                .setIssuer(appleTeamId)
                .setAudience(audience)
                .setSubject(appleClientId)
                .setExpiration(expiresAt)
                .setIssuedAt(issuedAt)
                .signWith(SignatureAlgorithm.ES256, pKey)
                .compact();
    }
}

电话是:

@Value("${apple.keyId}")
public String appleKeyId;

@Value("${apple.teamId}")
public String appleTeamId;

@Value("${apple.certificateResourcePath}")
public String appleCertificateResourcePath;

@Value("${apple.clientId}")
public String appleClientId;

...

@SuppressWarnings("unchecked")
private boolean validateAppleIdToken(String authorizationCode) {
    final String appleAuthUrl = "https://appleid.apple.com/auth/token";
    try {
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

        MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
        map.add("client_id", appleClientId);
        String token = appleIdTokenFactory.createAppleIdTokenAsString(
                appleCertificateResourcePath,
                appleKeyId,
                appleTeamId,
                appleClientId
        );
        map.add("client_secret", token);
        map.add("grant_type", "authorization_code");
        map.add("code", authorizationCode);  // JWT code we got from iOS
        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);

        restTemplate.postForObject(appleAuthUrl, request, String.class);

        return true;
    } catch (Exception e) {
        LOG.error("Exception occured while validating AppleId client token", e);
        return false;
    }
}

无论我做什么,我都会得到 HTTP 代码 400。此外,我无法真正调试它——它不会返回任何额外的数据,只是返回 HTTP 400。

是否有用于此的调试工具或端点?

我试过了:

没有任何帮助,错误仍然相同,我不知道如何调试它。有什么帮助吗?

标签: javavalidationauthenticationapple-id

解决方案


推荐阅读