maven 依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>jwks-rsa</artifactId>
<version>0.9.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
Service业务处理
//第零步:前端授权处理,传identityToken给到后端
//第一步:验证identityToken
//第二步:对identityToken解码,获取苹果账号的openId(唯一标识)
public JSONObject appleLogin(String identityToken) throws Exception {
JSONObject jsonObject = new JSONObject();
log.info("苹果 identityToken,{}", identityToken);
//第一步:验证identityToken
if (!AppleUtils.verify(identityToken)) {
throw new Exception("授权验证失败");
}
log.info("苹果授权验证成功!");
//第二步:对identityToken解码
JSONObject json = AppleUtils.parserIdentityToken(identityToken);
if (json == null) {
throw new Exception("授权解码失败");
}
log.info("返回认证信息 :{}", json);
String openId = (String) json.get("sub");
if (StringUtils.isBlank(openId)) {
throw new Exception("未获取到openId信息");
}
//TODO 获取到苹果的 openId 后,做自己的业务逻辑处理
return jsonObject;
}
苹果校验相关的工具类
package com.devinx.user.util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwk.Jwk;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import java.security.PublicKey;
/**
* @ClassName AppleUitls
* @Author devin xu
* @Description Apple授权登录相关
* @Date 2021/7/19 001913:46
* @Version 1.0
**/
@Slf4j
@Component
public class AppleUtils {
/**
* 获取苹果的公钥
*
* @return
* @throws Exception
*/
private static JSONArray getAuthKeys() {
log.info("获取苹果公钥");
String url = "https://appleid.apple.com/auth/keys";
RestTemplate restTemplate = new RestTemplate();
JSONObject json = restTemplate.getForObject(url, JSONObject.class);
if (json != null) {
return json.getJSONArray("keys");
}
return null;
}
public static Boolean verify(String jwt) throws Exception {
//获取公钥
JSONArray arr = getAuthKeys();
log.info("公钥key数组,{}", arr);
if (arr == null) {
return false;
}
JSONObject authKey;
for (int i = 0; i < arr.size(); i++) {
//取苹果key进行校验
String jsonString = JSONObject.toJSONString(arr.get(i));
authKey = JSONObject.parseObject(jsonString);
if (verifyExc(jwt, authKey)) {
log.info("第{}次进行校验通过;", (i + 1));
return true;
}
}
return false;
}
/**
* 对前端传来的identityToken进行验证
*
* @param jwt 对应前端传来的 identityToken
* @param authKey 苹果的公钥 authKey
* @return
* @throws Exception
*/
public static Boolean verifyExc(String jwt, JSONObject authKey) throws Exception {
Jwk jwa = Jwk.fromValues(authKey);
PublicKey publicKey = jwa.getPublicKey();
String aud = "";
String sub = "";
if (jwt.split("\\.").length > 1) {
String claim = new String(Base64.decodeBase64(jwt.split("\\.")[1]));
aud = JSONObject.parseObject(claim).get("aud").toString();
sub = JSONObject.parseObject(claim).get("sub").toString();
}
JwtParser jwtParser = Jwts.parser().setSigningKey(publicKey);
jwtParser.requireIssuer("https://appleid.apple.com");
jwtParser.requireAudience(aud);
jwtParser.requireSubject(sub);
log.info("解析 jwt ,aud ,{}", aud);
log.info("解析 jwt ,sub ,{}", sub);
try {
Jws<Claims> claim = jwtParser.parseClaimsJws(jwt);
if (claim != null && claim.getBody().containsKey("auth_time")) {
log.info(claim);
return true;
}
} catch (Exception e) {
log.info("根据公钥对identityToken验证不通过");
return false;
}
return false;
}
/**
* 对前端传来的JWT字符串identityToken的第二部分进行解码
* 主要获取其中的aud和sub,aud大概对应ios前端的包名,sub大概对应当前用户的授权的openID
*
* @param identityToken
* @return {"aud":"com.xkj.****","sub":"000***.8da764d3f9e34d2183e8da08a1057***.0***","c_hash":"UsKAuEoI-****","email_verified":"true","auth_time":1574673481,"iss":"https://appleid.apple.com","exp":1574674081,"iat":1574673481,"email":"****@qq.com"}
*/
public static JSONObject parserIdentityToken(String identityToken) {
String[] arr = identityToken.split("\\.");
Base64 base64 = new Base64();
String decode = new String(base64.decodeBase64(arr[1]));
String substring = decode.substring(0, decode.indexOf("}") + 1);
JSONObject jsonObject = JSON.parseObject(substring);
return jsonObject;
}
}