java - 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。
是否有用于此的调试工具或端点?
我试过了:
- 其他 HTTP 客户端,
- HTTP 放置,
- JWT 令牌而不是身份验证码,
- 将部分标记反转为 text1.text2.0.text3 格式(请参阅:invalid_client for sign in with apple)
没有任何帮助,错误仍然相同,我不知道如何调试它。有什么帮助吗?
解决方案
推荐阅读
- web-scraping - 有没有办法防止内容缓存或从 API 中抓取?
- flutter - 附加到多个滚动视图的 ScrollController 断言失败:第 109 行 pos 12:'_positions.length == 1'
- android - Kotlin AndroidStudio 类型不匹配
- c++ - C++ std::function 参数 const 参考
- python - 如何使用 csv.dictreader 打印数据记录数?
- javascript - 检查是元素是在 JavaScript 中包装文本的最后一个节点
- python - Python 线程计数器
- vue.js - 如何一次处理 Vuex 中的对象突变
- youtube-dl - youtube-dl 和 aria2c - 基于带有 YouTube 链接的列表批量下载并根据文件名列表保存每个文件
- python - Visual Studio Code:当我检查 3 次时弹出“无效语法”