先吐槽!苹果开发文档就是S
好了,开发步骤:
1.导入JWT Maven
<dependency>
<groupId>io.jsonwebtokengroupId>
<artifactId>jjwtartifactId>
<version>0.9.0version>
dependency>
2.首先闭上眼睛,以GET方式不带参数访问 https://appleid.apple.com/auth/keys,获取最新JSON,对我们有用的就是"n"和"e",组成JWT公钥。
获取到的json内容:
{
"keys": [
{
"kty": "RSA",
"kid": "AIDOPK1",
"use": "sig",
"alg": "RS256",
"n": "lxrwmuYSAsTfn-lUu4goZSXBD9ackM9OJuwUVQHmbZo6GW4Fu_auUdN5zI7Y1dEDfgt7m7QXWbHuMD01HLnD4eRtY-RNwCWdjNfEaY_esUPY3OVMrNDI15Ns13xspWS3q-13kdGv9jHI28P87RvMpjz_JCpQ5IM44oSyRnYtVJO-320SB8E2Bw92pmrenbp67KRUzTEVfGU4-obP5RZ09OxvCr1io4KJvEOjDJuuoClF66AT72WymtoMdwzUmhINjR0XSqK6H0MdWsjw7ysyd_JhmqX5CAaT9Pgi0J8lU_pcl215oANqjy7Ob-VMhug9eGyxAWVfu_1u6QJKePlE-w",
"e": "AQAB"
}
]
}
我使用restTemplate方式请求,并组成公钥:
public PublicKey getPublicKey() {
try {
String forObject = restTemplate.getForObject(AUTH_DOMAIN, String.class);
if(StringUtils.isEmpty(forObject)){ return null; }
AppleKeys appleKeys = JsonUtils.parseObject(forObject, AppleKeys.class);
List<AppleKeys.Keys> keys = appleKeys.getKeys();
String n = keys.get(0).getN();
String e = keys.get(0).getE();
final BigInteger modulus = new BigInteger(1, Base64.decodeBase64(n));
final BigInteger publicExponent = new BigInteger(1, Base64.decodeBase64(e));
final RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, publicExponent);
final KeyFactory kf = KeyFactory.getInstance(RSA);
return kf.generatePublic(spec);
} catch (final Exception e) {
log.debug("[APPLE]ERROR:{}",e)
}
return null;
}
3.IOS客户端经过一系列操作获取到:identityToken,userID等。将identityToken传递到后台(其他参数没啥用)
4.后台取到 identityToken 是jwt格式(固定三段式以“.”切割…我们只需要取第二段即可),然后使用Base64解析出来,对我们有用的数据只有三个字段:
"iss"=https://appleid.apple.com(固定签名);
"aud"=APPID
"sub"=**用户的唯一标识**(所以前端不需要额外传递userID)
String [] identityTokens = identityToken.split("\\.");
Map<String, Object> data = JsonUtils.parseMap(new String(Base64.decodeBase64(identityTokens[1]),"UTF-8"),String.class, Object.class);
String iss = (String) data.get("iss");
String aud = (String) data.get("aud");
String sub = (String) data.get("sub");
5.将"identityToken"和上一步解析出来的"iss",“aud”,"sub"传入一下方法验证JWT是否有效,返回true即等于没问题:
public boolean verify(String identityToken,String iss,String aud,String sub) {
PublicKey publicKey = getPublicKey();
JwtParser jwtParser = Jwts.parser().setSigningKey(publicKey);
jwtParser.requireIssuer(iss);
jwtParser.requireAudience(aud);
jwtParser.requireSubject(sub);
try {
Jws<Claims> claim = jwtParser.parseClaimsJws(identityToken);
if (null != claim && claim.getBody().containsKey(AUTH_TIME_STR)) {
return true;
}
return false;
} catch (ExpiredJwtException e) {
return false;
} catch (Exception e) {
return false;
}
}
6.ORM操作忽略