Sign in with Apple(苹果授权登陆)服务端验证-测试通过版
苹果登录方式有2种,这里介绍基于JWT算法验证
废话不多说,上代码
1.先引用2个jwt用到的jar包
<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>
2.算法的工具类
package com.imc.common;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwk.Jwk;
import io.jsonwebtoken.*;
import org.apache.commons.codec.binary.Base64;
import java.security.PublicKey;
import java.util.HashMap;
/**
* <br>
* date:2012/03/26 9:43
*
* @author xh
* @version 1.0
* @since JDK 1.8
*/
public class SignInWithAppleHelper {
/**
* 解密个人信息
*
* @param identityToken APP获取的identityToken
* @return 解密参数:失败返回null
*/
public String verify(String identityToken) {
try {
if (identityToken.split("\\.").length > 1) {
String claim = new String(Base64.decodeBase64(identityToken.split("\\.")[1]));
String aud = JSONObject.parseObject(claim).get("aud").toString();
String sub = JSONObject.parseObject(claim).get("sub").toString();
String reuslt = this.verify(this.getPublicKey(), identityToken, aud, sub);
if (reuslt.equals("SUCCESS")) {
System.out.println("苹果登录成功");
return claim;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static String verify(PublicKey key, String jwt, String audience, String subject) throws Exception {
String result = "FAIL";
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")) {
result = "SUCCESS";
return result;
}
} catch (ExpiredJwtException e) {
throw new Exception("苹果token过期", e);
} catch (SignatureException e) {
throw new Exception("苹果token非法", e);
}
return result;
}
/**
* 从hex string生成公钥
*
* @return 构造好的公钥
*/
public PublicKey getPublicKey() {
try {
String str = HttpHelper.get("https://appleid.apple.com/auth/keys", new HashMap<String, String>());
JSONObject data = JSONObject.parseObject(str);
String keys = data.getString("keys");
JSONArray arr = JSONObject.parseArray(keys);
JSONObject jsonObject1 = JSONObject.parseObject(arr.getString(0));
Jwk jwa = Jwk.fromValues(jsonObject1);
PublicKey publicKey = jwa.getPublicKey();
return publicKey;
} catch (final Exception e) {
e.printStackTrace();
}
return null;
}
}
三方登录调用验证工具类
仔细看,很多文档都没有的东西来了,我这块用到了缓存,为什么用缓存呢,因为这块代码在我反复测试的情况下,移动端给的identityToken参数你频繁操作的话jwt验证会报错,在本楼主大量实验的情况下测试出 一个userID 对应的identityToken有效期是10分钟,userID是苹果给用户的唯一标识,所以我把userID当做key ,把identityToken存到redis内,我这里缓存是9分钟,我是考虑到网络IO等,反正不差那1分钟,经测试没问题,产品逻辑可适当修改
if (type == Constants.LOGIN_TYPE_APPLE) {
//苹果登陆使用参数
String identityToken = params.getString("identityToken");
//苹果登录唯一表示
thirdLoginId = params.getString("userID");
if (redisCacheUtil.get(thirdLoginId) != null) {
identityToken = redisCacheUtil.get(thirdLoginId) + "";
}
//这里可以根据thirdLoginId查询数据库是否存在,如果存在就返回用户信息
//苹果登陆验证
SignInWithAppleHelper signInWithAppleHelper = new SignInWithAppleHelper();
String data = signInWithAppleHelper.verify(identityToken);
if (data != null) {
//苹果登录唯一表示
thirdLoginId = JSONObject.parseObject(data).get("sub").toString();
if (redisCacheUtil.get(thirdLoginId) == null) {
redisCacheUtil.set(thirdLoginId, identityToken, 540);
}
} else {
throw new CustomException(code_3010, "与苹果服务器链接超时,请重新尝试。");
}
}
不喜勿喷,感谢各位大大的阅读🥰