import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.rrk.common.center.bin.exception.RrkException;
import com.rrk.common.center.tool.http.HttpUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.Jwts;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.RSAPublicKeySpec;
public class AppleAuthUtils {
private static final Logger LOG = LoggerFactory.getLogger(AppleAuthUtils.class);
private static final String AUTH_URL = "https://appleid.apple.com/auth/keys";
/**
* 验证授权信息是否有效
*
* @param identityToken
* @param appleAccount
* @return
*/
public static boolean verify(String identityToken, String appleAccount) {
String[] identityData = StringUtils.split(identityToken, ".");
if (identityData.length == 0) {
return false;
}
try {
String headStr = new String(Base64.decodeBase64(identityData[0]), "utf-8");
JSONObject headData = JSONObject.parseObject(headStr);
// 公钥id标识
String kid = headData.getString("kid");
String identityStr = new String(Base64.decodeBase64(identityData[1]), "utf-8");
JSONObject data = JSONObject.parseObject(identityStr);
System.out.println(data);
// 对比iOS客户端传过来的用户唯一标识是否和授权凭证一致
if (!appleAccount.equals(data.getString("sub"))) {
LOG.info("Apple登录授权用户信息不一致");
throw new RrkException("Apple登录授权用户信息不一致");
}
JwtParser jwtParser = Jwts.parser().setSigningKey(AppleAuthUtils.buildAuthPublicKey(kid));
jwtParser.requireIssuer(data.getString("iss"));
// iOS应用标识
jwtParser.requireAudience(data.getString("aud"));
// 用户的唯一标识
jwtParser.requireSubject(data.getString("sub"));
Jws<Claims> claims = jwtParser.parseClaimsJws(identityToken);
if (claims != null && claims.getBody().containsKey("auth_time")) {
return true;
}
} catch (Exception e) {
LOG.error("验证Apple登录授权信息失败,原因:", e);
throw new RrkException("验证Apple登录授权信息过期");
}
return false;
}
public static String getEmail(String identityToken, String appleAccount) {
String[] identityData = StringUtils.split(identityToken, ".");
if (identityData.length == 0) {
return "";
}
try {
String identityStr = new String(Base64.decodeBase64(identityData[1]), "utf-8");
JSONObject data = JSONObject.parseObject(identityStr);
return data.get("email").toString();
} catch (Exception e) {
LOG.error("验证Apple登录授权信息失败,原因:", e);
throw new RrkException("验证Apple登录授权信息过期");
}
}
/**
* 生成授权公钥
*
* @return
*/
private static PublicKey buildAuthPublicKey(String kid) {
try {
// 调用苹果接口获取公钥参数
String jsonStr =HttpUtils.get(AUTH_URL).getBody();
if (StringUtils.isEmpty(jsonStr)) {
return null;
}
JSONObject result = JSONObject.parseObject(jsonStr);
JSONArray keys = result.getJSONArray("keys");
if (keys == null || keys.size() == 0) {
return null;
}
JSONObject currentKey = null;
// 通常情况下返回值keys包含2个,需要根据kid来决定使用哪套公钥参数
for (int i = 0; i < keys.size(); i++) {
JSONObject key = keys.getJSONObject(i);
if (kid.equals(key.getString("kid"))) {
currentKey = key;
break;
}
}
if (currentKey == null) {
return null;
}
String n = currentKey.getString("n");
String e = currentKey.getString("e");
BigInteger modulus = new BigInteger(1, Base64.decodeBase64(n));
BigInteger publicExponent = new BigInteger(1, Base64.decodeBase64(e));
RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, publicExponent);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePublic(spec);
} catch (Exception e) {
LOG.error("生成Apple登录授权公钥出错,原因:", e);
}
return null;
}