苹果登录的服务端验证原理和实现

  • 前言
  • 铺垫知识(会的可以直接跳过)
  • APPLE的登录原理
  • 实现(Java)

前言

为什么要用苹果登录?在国内大多数人应该都是使用的微信登录或者手机号一键登录多一些。之所以要开发苹果登录,可能大多是因为苹果的霸王条款:要求只要在苹果商店上架的应用,凡是接入了其他第三方登录,必须接入苹果登录。

虽然苹果的霸王条款很让人恼火,但是苹果登录本身还是值得我们学习和思考的。下面介绍一下苹果登录的原理。

铺垫知识(会的可以直接跳过)

在学习苹果登录之前,首先你需要了解以下几个知识点:

  1. 什么是非对称加密,什么是公钥和私钥?
  2. 什么是JWT,这东西是用来干嘛的?
  3. 什么是第三方登录?

下面依次给大家简要介绍一下上面三个知识点:

  • 非对称加密
    我们知道对称加密在加解密时使用的秘钥内容是相同的,而非对称加密在加密和解密时使用不同的秘钥。我们把这两个不同的秘钥一个称为私钥,一个称为公钥。一般私钥由我们自己保留不对外公开,而公钥则可以对外公开下载。这样有什么好处呢?举个例子:我们发布一则公告,使用私钥进行加密,然后把公告放到互联网上。想要看公告的人直接下载我们的公钥,然后用公钥解密公告即可。这样别人就无法仿造我们的公告,因为只有我们提供的公钥才能解密,从而达到对公告信任的目的。

  • JWT是什么
    JWT是什么?直接回答这个问题比较难以理解,我们就拿苹果的JWT举个例子:

{"kid": "W6WcOKB","alg": "RS256"}.{"iss":"https://appleid.apple.com","aud":"com.test","exp":1687776521,"iat":1687690121,"sub":"001001.0bb42737edf44688850c5de5e666d9e.1024","c_hash":"FXhhsDY1Dpabo8_GTID-Lw","auth_time":1687690121,"nonce_supported":true,"real_user_status":2}.xxxxxxxxxxxxxxxxxxxxxxxxxx

我们看到jwt就是一个字符串,由三段字符串组成。

  1. 第一段:{"kid": "W6WcOKB","alg": "RS256"}我们称为头部,标记了这个JWT通过RS256进行加密,(这里的kid是对应的公钥id,这个是苹果特有的)。
  2. 第二段:{"iss":"https://appleid.apple.com","aud":"com.test","exp":1687776521,"iat":1687690121,"sub":"001001.0bb42737edf44688850c5de5e666d9e.1024","c_hash":"FXhhsDY1Dpabo8_GTID-Lw","auth_time":1687690121,"nonce_supported":true,"real_user_status":2}
    这里我们只说关键的几个参数:iss:发布人,固定是苹果的域名;aud:应用的包名;sub:当前用户的唯一ID,类似微信等第三方登录的OpenID;
  3. 第三段:就是校验和类似的东西,没有详细的研究苹果是怎么实现的,但是我们理解技术不必太过纠结,知道他是个校验和的东西就行。比如我可以这么实现,首先将前面的两个部分拼接成一个字符串,然后求一个摘要,再用私钥进行加密后作为第三部分。需要校验时,先求前两部分摘要,然后用公钥解密第三方部分,看解密的结果和我们求出的摘要是否相等即可。
  • 什么是第三方登录?
    其实问为什么需要第三方登录更好。随着我们使用的应用越来越多,如果我们每个都创建一个账户和密码,简直就是噩梦。而我们有微信账号,如果可以直接用微信账号登录多好,一个账号走天下,只要记住微信的密码,能登录微信就可以了,再也不怕忘记密码了。至于通常如何实现第三方登录,可以去了解下OAuth2,这里就不再多说了,不是本文的重点。

APPLE的登录原理

  1. 首先,当你在应用内点击苹果登陆按钮时,苹果会生成一系列的参数给你,其中最重要的一个参数是:identityToken。这个参数的值就是一个JWT。这个JWT是通过苹果的私钥加密的。
  2. 我们将这个identityToken传给我们的后台服务,后台服务从苹果提供的公钥下载地址下载公钥,然后使用公钥验证这个JWT是否合法。
  3. 在合法的前提下,我们看一下iss是否是苹果(显然是),再看aud是不是你自己的包名(别人的应用也可以生成一个token,也可以通过校验,但是包名肯定和你的不同)。都校验通过了,说明这是一个合法JWT。然后我们就取sub作为苹果的OpenId,记录到我们后台的用户表里即可(如果没有用户则创建,如果有则绑定)。等到再次登录的时候,则用sub查询有没有对应的用户,如果有,则直接让其登录即可。

实现(Java)

引入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.22.0</version>
</dependency>

实现代码(以下代码复制就可以直接使用):

  • 校验代码(核心逻辑)
public class AppleAuthHelper {private static final String PUBLIC_KEY_URL = "/auth/keys";private static final String APPLE_DOMAIN = "https://appleid.apple.com";private static final String aud = "com.test";public static boolean isValid(AppleAuthRequest appleAuthRequest) {try {IdentityToken idToken = new IdentityToken(appleAuthRequest.getIdentityToken());String userID = appleAuthRequest.getUserID();PublicKey publicKey = AppPublicKey.get(APPLE_DOMAIN + PUBLIC_KEY_URL, idToken.getKid());if (null == publicKey) {return false;}JwtParser jwtParser = Jwts.parser().setSigningKey(publicKey);jwtParser.requireIssuer(APPLE_DOMAIN);jwtParser.requireAudience(aud);jwtParser.requireSubject(userID);Jws<Claims> claim = jwtParser.parseClaimsJws(idToken.getToken());if (claim != null && claim.getBody().containsKey("auth_time")) {return true;}} catch (Exception e) {log.error("校验apple登录信息失败", e);}return false;}
}
  • 获取公钥代码
public class AppPublicKey {public static volatile Map<String, Map<String, Object>> cache = new HashMap<>();public static PublicKey get(String url, String kid) {try {if (cache.containsKey(kid)) {Map<String, Object> publicKeyConfig = cache.get(kid);Jwk jwa = Jwk.fromValues(publicKeyConfig);return jwa.getPublicKey();}Map<String, Object> publicKeyConfig = getPublicKeyConfig(url, kid);if (null == publicKeyConfig) {return null;}Jwk jwa = Jwk.fromValues(publicKeyConfig);return jwa.getPublicKey();} catch (final Exception e) {log.error("apple get publicKey error", e);}return null;}private static synchronized Map<String, Object> getPublicKeyConfig(String url, String kid) {try {String str = HttpUtil.get(url);JsonNode jsonNode = JsonHelper.asTree(str);JsonNode keys = jsonNode.get("keys");if (null == keys) {return null;}Iterator<JsonNode> elements = keys.elements();while (elements.hasNext()) {JsonNode node = elements.next();String nodeKid = node.get("kid").asText();if (kid.equals(nodeKid)) {Map<String, Object> item = JsonHelper.toMap(node);cache.put(nodeKid, item);}}return cache.get(kid);} catch (final Exception e) {log.error("apple get publicKey error", e);}return null;}
}
  • 辅助类(请求参数等)
public class AppleAuthRequest {private String authorizationCode;private String identityToken;private String userID;private AppleUserInfo fullName;
}public class AppleUserInfo {private String givenName;private String familyName;private String middleName;private String namePrefix;private String nameSuffix;private String nickname;private String phoneticRepresentation;
}public class IdentityToken {//原始tokenprivate String token;//公钥idprivate String kid;//应用包名,应该为:com.testprivate String aud;//用户openIdprivate String sub;@SneakyThrowspublic IdentityToken(String token) {this.token = token;String[] identityTokens = this.token.split("\\.");Map<String, Object> firstDate = JSONObject.parseObject(new String(Base64.decodeBase64(identityTokens[0]), "UTF-8"));Map<String, Object> secondData = JSONObject.parseObject(new String(Base64.decodeBase64(identityTokens[1]), "UTF-8"));this.kid = String.valueOf(firstDate.get("kid"));this.aud = String.valueOf(secondData.get("aud"));this.sub = String.valueOf(secondData.get("sub"));}
}public class JsonHelper {private final static ObjectMapper objectMapper = new ObjectMapper();public static Map<String,Object> toMap(JsonNode jsonNode){return objectMapper.convertValue(jsonNode, new TypeReference<Map<String, Object>>(){});}public static JsonNode asTree(String strJson) {try {return objectMapper.readTree(strJson);} catch (IOException e) {log.error("Deserialize fail", e);}return null;}
}

【苹果登录】使用Apple账号登录你的APP(服务端原理介绍+Java实现)相关推荐

  1. 一键登录服务端原理_一键登录已成大势所趋,Android端操作指南来啦!

    根据极光(Aurora Mobile)发布的<2019年Q2移动互联网行业数据研究报告>,2019年第二季度,移动网民人均安装APP总量已达56款.面对如此繁多的APP,想在用户的手机中占 ...

  2. SSO单点登录详解-------八、搭建CAS Client服务端

    一.前言 目前为止我们已经搭建好了CAS Server端,我们需要来搭建客户端配合使用,完成单点登录和单点注销的功能.我们将讲两种方式来搭建CAS Client端.一种是普通项目搭建,另一种是基于Sp ...

  3. macOS微信客户端插件,支持免认证登录、多账号登录以及防撤回

    WeChatTweak是一款微信第三方插件,目前仅Mac版的微信客户端.支持功能有「防撤回」和「多账户登录」,最方便的还有「免手机验证登录」,以后终于不用在手机端确定登录了! 因为WeChatTwea ...

  4. php清除账号登录,php实现账号登录/上传/下载/删除文件

    环境:Ubuntu16.04 搭建apache+mysql+php 1.安装apache sudo apt-get update sudo apt-get install apache2 安装完后输入 ...

  5. 一键登录服务端原理_本机号码一键登陆是什么原理?

    一直在关注该问题,尤其是h5通过流量获取本机手机号.网上也查了很多相关的资料,但是没有专业的答案,因为这个涉及运营商对流量数据的获取,个人认为是除了应用层外,还涉及网络层.传输层甚至数据链路层多个层面 ...

  6. 修改手游登录服务器,手游[有侠气]一键启动服务端+客户端+GM管理运营后台+VIP修改+启动教程等...

    内容介绍 资源说明: 1.本资源默认IP为192.168.1.110,本机网络为1网段用户可将本机IP设置为192.168.1.110后直接按照教程步骤启动游戏,同时支持手机WIFI局域网使用. 2. ...

  7. ios 自己服务器 苹果支付_iOS应用内支付(IAP)服务端端校验详解

    { "status": 0, "environment": "Sandbox", "receipt": { " ...

  8. 征服账号服务器,最新中文征服服务端(带架设教程+客户端补丁+需要的工具)10.13日更新...

    最新中文征服服务端(带架设教程+客户端补丁+需要的工具)10.13日更新 10月9号版本更新信息: 增加了 头像. 头像已经很完美了 天石 , 挖矿, 宝石效果 高级宝石 可以放出 动画 数据库已经改 ...

  9. apple登录服务端验证

    Sign In With Apple 从登陆到服务器验证 服务端向苹果请求验证 手机端需要提交 user .authorizationCode . identityToken 字段信息(code和to ...

  10. flutter在IOS上的登录实现——QQ登录、微信登录、自动识别手机号一键登录、apple登录

    flutter在IOS上的登录实现--QQ登录.微信登录.自动识别手机号一键登录.apple登录 一.QQ登录 使用的第三方库: 具体操作方法: 1.配置 Universal Links 2.QQ互联 ...

最新文章

  1. 一键安装GitLab7在RHEL6.4上
  2. BZOJ 1920 Luogu P4217 [CTSC2010]产品销售 (模拟费用流、线段树)
  3. 田忌赛马c语言程序设计,还是杭电1052田忌赛马
  4. iis7 php5 isapi配置,Windows7 IIS7下以FastCgi和ISAPI方法安装配置PHP5教程
  5. python 异常分类_Python异常类型
  6. unsigned char bcd串乱码问题解决
  7. 计算机视觉(三)——人脸识别
  8. 【模拟】牛客网:顺时打印矩阵
  9. SPEI不同时间尺度的意义
  10. IDEA安装Vue插件
  11. 在华为做测试员是一种什么体验?带你深入了解华为
  12. 移动统计工具Flurry
  13. SSL,HTTPS,数字证书 是什么?
  14. 工作流模式的学习与总结
  15. 用python计算整数各位数字之和
  16. UINO优诺:数字孪生可视化管理GIV,打造统览全局大视野
  17. 关于两个周期函数的和的周期性的讨论
  18. 图神经网络12-分子指纹GCN:Neural FPs
  19. php中表格第一行不动,word表格行高拉不动怎么办
  20. 分享十款国外最受欢迎的搜索引擎

热门文章

  1. 企业即时通讯软件怎样改变企业内部通信方式?
  2. LegalAI公开数据集的整理、总结及介绍(持续更新ing…)
  3. algo查询学习笔记
  4. 【转载】罗胖 60 秒:说出去就不灵了
  5. ums-realtek问题
  6. 开学第一堂线下课——计算机系统结构
  7. 深度学习之电影二分类的情感问题
  8. 从电子垃圾中提炼黄金,可以!!!
  9. 国防科技大学计算机考研试题,国防科技大学历年操作系统考研试题
  10. 计算机桌面不显示存储卡,电脑主机开了为什么屏幕显示不出来