背景:业务更换了应用苹果开发者账号主体,导致用户使用苹果登录后服务端获取到的用户标识不一样。微信登录有openid和unionid的概念,苹果没有在不同应用下用户唯一的标识,也就是unionid,但苹果提供了用户迁移的功能:如何将老主体的用户标识迁移到新主体下。
迁移过程分成两步:
1、old sub => transtrnaferSub 苹果文档
将老主体应用的sub 变成一个中间状态标识 ,为什么有这个中间状态可能是为了避免泄露sub吧。
2、transtrnaferSub => new sub 苹果文档
new sub 就是新主体应用下的用户标识了。
具体细节看苹果文档就行了,相关代码:
获取accessToken
public static String accessToken(String privateKey, String keyId, String teamId) {
Map<String, Object> param = new HashMap<>();
param.put("grant_type", "client_credentials");
param.put("scope", "user.migration");
param.put("client_id", "your clientId");
param.put("client_secret", clientSecret(privateKey, keyId, teamId));
String result = HttpClientFactory.invokePost("https://appleid.apple.com/auth/token", param, "utf-8", 5000, 5000);
JsonNode jsonNode ;
try {
jsonNode = mapper.readTree(result);
} catch (JsonProcessingException e) {
log.error("json parse error. json = {}", result, e);
return "";
}
JsonNode accessToken = jsonNode.get("access_token");
if (accessToken == null || accessToken.isNull()) {
log.error("apple response error. result = {}", result);
return "";
}
return accessToken.asText();
}
获取 clientSecret
private static String clientSecret(String privateKey, String keyId, String teamId) {
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.ES256;
PrivateKey key = null;
try {
key = generateKey(privateKey);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
} catch (NoSuchProviderException e) {
throw new RuntimeException(e);
} catch (InvalidKeySpecException e) {
throw new RuntimeException(e);
}
Map<String, Object> header = new HashMap<>();
header.put("alg", "ES256");
header.put("kid", keyId);//key_id
JwtBuilder jwtBuilder = Jwts.builder()
.setHeader(header)
.setSubject("your subject")
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 5*60*1000))
.setAudience("https://appleid.apple.com")
.setIssuer(teamId)//team_id
.signWith(key, signatureAlgorithm);
return jwtBuilder.compact();
}
获取签名私钥:
key就是p8文件里的内容
public static PrivateKey generateKey(String key) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException {
String privateKey = key.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s+", "");
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
// 生成私匙
KeyFactory kf = KeyFactory.getInstance("ECDH", "BC");
return kf.generatePrivate(
new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
}
苹果用户迁移是单向的,只能由旧转新,并且要在60天内完成。迁移的时候要提前准备好,保留好旧的p8证书,规划好迁移策略。我们实际迁移的时候选择一次性把所有历史数据刷一遍。