Java对接苹果账号授权登录

您所在的位置:网站首页 苹果账号授权app Java对接苹果账号授权登录

Java对接苹果账号授权登录

2024-07-17 06:19| 来源: 网络整理| 查看: 265

背景:

项目中app登录有第三方账号授权登录,在今年6月30号以后,苹果对发布的app中若有第三方账号授权,必须得接入苹果账号的授权登录的硬性要求。不然在发版时,会不通过审核

苹果授权流图

在这里插入图片描述

代码实现

maven的依赖:

io.jsonwebtoken jjwt 0.9.1

通过RestTemplate发起请求获取苹果的公钥信息:

public PublicKey getPublicKey(String kid) { logger.debug("get public key start,kid={}", kid); try { HeaderMap headerMap = new HeaderMap(); headerMap.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_PROBLEM_JSON_UTF8_VALUE); headerMap.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_UTF8_VALUE); AppleKeyResponse appleKeyResponse = get(GET_KEY_URL, headerMap, new ResponseType() { }); logger.debug("get public key success,appleKeyResponse={}", appleKeyResponse); if (null == appleKeyResponse || CollectionUtils.isEmpty(appleKeyResponse.getKeys())){ return null; } List appleKeyVos = appleKeyResponse.getKeys(); for (AppleKeyVo appleKeyVo : appleKeyVos) { if (kid.equals(appleKeyVo.getKid())) { BigInteger modulus = new BigInteger(1, Base64.decodeBase64(appleKeyVo.getN())); BigInteger publicExponent = new BigInteger(1, Base64.decodeBase64(appleKeyVo.getE())); RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, publicExponent); KeyFactory kf = KeyFactory.getInstance("RSA"); return kf.generatePublic(spec); } } } catch (Exception e) { logger.error("get public key fail,e={}", e); } return null; }

注意 1、GET_KEY_URL =https://appleid.apple.com/auth/keys 2、get(GET_KEY_URL, headerMap, new ResponseType() {});这里的get方法,是公司封装RestTemplate的get请求方法。 3、获取到苹果公钥是一个数组,需要根据从前端传过来的identityToken中解析对应的kid(密钥id),如何解析,参考下面的解析identityToken代码

AppleKeyResponse 类

public class AppleKeyResponse { private List keys; public List getKeys() { return keys; } public void setKeys(List keys) { this.keys = keys; } @Override public String toString() { return "AppleKeyResponse{" + "keys=" + keys + '}'; }

AppleKeyVo 类

public class AppleKeyVo { /** * 加密算法 */ private String kty; /** * 密钥id */ private String kid; /** * 用处 */ private String use; /** * 算法 */ private String alg; /** * 公钥参数 */ private String n; /** * 公钥参数 */ private String e; public String getKty() { return kty; } public void setKty(String kty) { this.kty = kty; } public String getKid() { return kid; } public void setKid(String kid) { this.kid = kid; } public String getUse() { return use; } public void setUse(String use) { this.use = use; } public String getAlg() { return alg; } public void setAlg(String alg) { this.alg = alg; } public String getN() { return n; } public void setN(String n) { this.n = n; } public String getE() { return e; } public void setE(String e) { this.e = e; } @Override public String toString() { return "AppleKeyVo{" + "kty='" + kty + '\'' + ", kid='" + kid + '\'' + ", use='" + use + '\'' + ", alg='" + alg + '\'' + ", n='" + n + '\'' + ", e='" + e + '\'' + '}'; }

解析identityToken(是苹果账号生成的授权码)

/** * 苹果工具类 * * @author : * @version : 1.0.0 * @date : 2020/7/13 17:10 */ public class AppleUtil { private static Logger logger = LoggerFactory.getLogger(AppleUtil.class); private static final String AUTH_TIME = "auth_time"; private static final String APPLE_SERVER_ULR = "https://appleid.apple.com"; /*public static void main(String[] args) { AppleTokenVo appleTokenVo = decodeIdentityToken("eyJraWQiOiJlWGF1bm1MIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL2FwcGxlaWQuYXBwbGUuY29tIiwiYXVkIjoiY29tLmNoYW5nZGFvLnR0c2Nob29sIiwiZXhwIjoxNTg5MjcwMzI3LCJpYXQiOjE1ODkyNjk3MjcsInN1YiI6IjAwMTk0MC43YTExNDFhYTAwMWM0NjllYTE1NjNjNmJhZTk5YzM3ZC4wMzA3IiwiY19oYXNoIjoienNIUW9xbTdjcDZOcmxrUHFhTmpGQSIsImVtYWlsIjoiYXEzMmsydnpjd0Bwcml2YXRlcmVsYXkuYXBwbGVpZC5jb20iLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJpc19wcml2YXRlX2VtYWlsIjoidHJ1ZSIsImF1dGhfdGltZSI6MTU4OTI2OTcyNywibm9uY2Vfc3VwcG9ydGVkIjp0cnVlfQ.q5unOzswOjpRYmrVKVm3FRb_Th6kkhgEvoFfTEAIETwgTXZ7bYcQM8J8tCjkGGqtt2z74Z-wTW7Q3ia209xhmwrVDIup0jcQgNTvsCEMkfo9evPIDrNRNQw2Dzw2EBKma8004NL6THYlySoDnPRoW_VQCHP_m0HnjYuIc-wtREEClf-_tOFDPpTsvUFoETHNfhpsLhqj24-zm6MSOocYY3WbUaYJQVEFCz-x6AGko1XkMtms_-JU1xakNtjMZTIVj2XyUI5MO7_eo-D9i_c7Hj-OE9HNBEvFnPxOesDzXvEoYdb7uByXEfa-H1syJMecBMRa3tL76W_CYKsONRkU9Q"); System.out.println(appleTokenVo); }*/ /** * 获取publicKey 的算法id * * @param identityToken 苹果token的第一部分 * @return String */ public static String getKid(String identityToken) { String kid = null; try { String str1 = new String(Base64.decodeBase64(identityToken), StandardCharsets.UTF_8); Map data1 = JSONUtil.readValue(str1, new TypeReference() { }); kid = (String) data1.get("kid"); } catch (Exception e) { logger.error("get kid fail,e={}", e); } return kid; } /** * 解密个人信息 * * @param identityToken APP获取的identityToken的第二部分 * @return 解密参数:失败返回null sub就是用户id,用户昵称需要前端传过来 */ public static AppleTokenVo getAppleUserInfo(String identityToken) { AppleTokenVo appleTokenVo = null; try { String str2 = new String(Base64Utils.decodeFromString(identityToken), StandardCharsets.UTF_8); appleTokenVo = JSONUtil.readValue(str2, AppleTokenVo.class); } catch (Exception e) { logger.info("get apple user information fail,e={} ", e); } return appleTokenVo; } /** * 验证 * * @param identityToken APP获取的identityToken * @param aud 您在您的Apple Developer帐户中的client_id * @param sub 用户的唯一标识符对应APP获取到的:user * @return true/false */ public static boolean verifyIdentityToken(PublicKey publicKey, String identityToken, String aud, String sub) { try { JwtParser jwtParser = Jwts.parser().setSigningKey(publicKey); jwtParser.requireIssuer(APPLE_SERVER_ULR); jwtParser.requireAudience(aud); jwtParser.requireSubject(sub); Jws claim = jwtParser.parseClaimsJws(identityToken); if (claim != null && claim.getBody().containsKey(AUTH_TIME)) { return true; } } catch (ExpiredJwtException e1) { logger.error("apple token verify fail,identityToken is expired!"); } catch (Exception e2) { logger.error("apple token verify fail,error={}", e2); } return false; } }

AppleTokenVo类(identityToken解析出来的信息):

/** * 苹果用户token中信息 * * @version : 1.0.0 * @date : 2020/7/17 15:03 */ public class AppleTokenVo { /** * 签发机构网址 */ private String iss; /** * bundle id */ private String aud; /** * 过期时间戳 */ private Long exp; /** * 签发时间 */ private Long iat; /** * user id */ private String sub; /** * 客户端发出请求时携带的随机串,用于对照 */ private String nonce; /** * 邮箱 */ private String email; public String getIss() { return iss; } public void setIss(String iss) { this.iss = iss; } public String getAud() { return aud; } public void setAud(String aud) { this.aud = aud; } public Long getExp() { return exp; } public void setExp(Long exp) { this.exp = exp; } public Long getIat() { return iat; } public void setIat(Long iat) { this.iat = iat; } public String getSub() { return sub; } public void setSub(String sub) { this.sub = sub; } public String getNonce() { return nonce; } public void setNonce(String nonce) { this.nonce = nonce; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } @Override public String toString() { return "AppleTokenVo{" + "iss='" + iss + '\'' + ", aud='" + aud + '\'' + ", exp=" + exp + ", iat=" + iat + ", sub='" + sub + '\'' + ", nonce='" + nonce + '\'' + ", email='" + email + '\'' + '}'; } } 总结:

苹果授权登录,代码大概就以上这些,除了公司封装RestTemplate,其他都有了。



【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3