最近随着iOS的更新,苹果要求含有第三方登录的app必须实现苹果登录功能,在查询相关资料后整合进自己的项目中,再次记录下,也供大家借鉴。
以下是大致流程,挺简单的:
首先引入解析jwt的包:
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>jwks-rsa</artifactId>
<version>0.9.0</version>
</dependency>
直接贴代码:
1.向苹果后台获取公钥参数(后台发送http请求工具类请自行配置,json转换工具也请自行使用)
**HttpClientResult httpClientResult = null;
try {
httpClientResult = HttpClientUtils.doGet("https://appleid.apple.com/auth/keys");
} catch (Exception e) {
throw new SysException("向苹果发送请求获取公钥失败", e);
}
JSONObject jsonObject = JSONObject.parseObject(httpClientResult.getContent());
String keys = jsonObject.getString("keys");
JSONArray arr = JSONObject.parseArray(keys);
JSONObject jsonObject1 = JSONObject.parseObject(arr.getString(0));**
ps 我们像苹果api获取的到的公钥参数格式如下(网上有很多对参数的解释):
```java
{"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"} ]}
上一步我们已经提取出该对象,接下来通过架包生成publicKey
Jwk jwa = Jwk.fromValues(jsonObject1);
PublicKey publicKey = jwa.getPublicKey();
第三步,分割前台传过来的identifyToken(jwt格式的token)用base64解码使用:
if (identifyToken.split("\\.").length > 1) {
String claim = new String(Base64.decodeBase64(jwt.split("\\.")[1]));
String aud = JSONObject.parseObject(claim).get("aud").toString();
String sub = JSONObject.parseObject(claim).get("sub").toString();
return Utils.verify(publicKey, jwt, aud, sub);
}
验证方法:
// 验证苹果公钥
public static String verify(PublicKey key, String jwt, String audience, String subject) {
JwtParser jwtParser = Jwts.parser().setSigningKey(key);
jwtParser.requireIssuer("https://appleid.apple.com");
jwtParser.requireAudience(audience);
jwtParser.requireSubject(subject);
try {
Jws<Claims> claim = jwtParser.parseClaimsJws(jwt);
if (claim != null && claim.getBody().containsKey("auth_time")) {
return "SUCCESS";
}
return "FAIL";
} catch (ExpiredJwtException e) {
throw new SysException("苹果token过期", e);
} catch (Exception e) {
throw new SysException("苹果token非法", e);
}
}
业务方法:
public String appleAuth(String jwt) {
HttpClientResult httpClientResult = null;
try {
httpClientResult = HttpClientUtils.doGet("https://appleid.apple.com/auth/keys");
} catch (Exception e) {
throw new SysException("向苹果发送请求获取公钥失败", e);
}
JSONObject jsonObject = JSONObject.parseObject(httpClientResult.getContent());
String keys = jsonObject.getString("keys");
JSONArray arr = JSONObject.parseArray(keys);
JSONObject jsonObject1 = JSONObject.parseObject(arr.getString(0));
Jwk jwa = Jwk.fromValues(jsonObject1);
try {
// 生成苹果公钥
PublicKey publicKey = jwa.getPublicKey();
// String hearder = new String(Base64.decodeBase64(jwt.split("\\.")[0]));
if (jwt.split("\\.").length > 1) {
String claim = new String(Base64.decodeBase64(jwt.split("\\.")[1]));
String aud = JSONObject.parseObject(claim).get("aud").toString();
String sub = JSONObject.parseObject(claim).get("sub").toString();
return Utils.verify(publicKey, jwt, aud, sub);
}
return "FAIL";
} catch (InvalidPublicKeyException e) {
throw new SysException("转换苹果公钥失败", e);
}
}
总结:找到4个参数调用验证方法即可。