苹果授权登陆方式

1. PC/M端授权登陆,采用协议类似于oauth2协议
2. App端授权登陆,提供两种后端验证方式

开发者后台配置

详细配置参考该文档,手把手教学
https://developer.okta.com/blog/2019/06/04/what-the-heck-is-sign-in-with-apple

1、 PC/M接入方式

  • https://appleid.apple.com/auth/authorize?response_type=code&client_id=&redirect_uri=&state=1234
  • 参考上面的后台配置,其中client_id对应的是Services ID,redirect_uri就是后台配置的接收code码的地址

2、APP端客户端授权登陆功能开发,可以参考如下文档

  • https://www.jianshu.com/p/23b46dea2076

重点讲解苹果授权登陆后端如何验证

针对后端验证苹果提供了两种验证方式,一种是基于JWT的算法验证,另外一种是基于授权码的验证

1、基于JWT的算法验证

  • 使用到的Apple公钥接口:https://appleid.apple.com/auth/keys
  • 详细接口文档说明参见:https://developer.apple.com/documentation/signinwithapplerestapi/fetch_apple_s_public_key_for_verifying_token_signature
  • 接口返回值:
{
"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"}
]
}

kid,为密钥id标识,签名算法采用的是RS256(RSA 256 + SHA 256),kty常量标识使用RSA签名算法,其公钥参数为n和e,其值采用了BASE64编码,使用时需要先解码

  • 使用方式:APP内苹果授权登陆会提供如下几个参数:userID、email、fullName、authorizationCode、identityToken

    • userID:授权的用户唯一标识
    • email、fullName:授权的用户资料
    • authorizationCode:授权code
    • identityToken:授权用户的JWT凭证

下面针对identityToken后端验证做简要说明:

  • identityToken参考样例:
// jwt 格式
eyJraWQiOiJBSURPUEsxIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL2FwcGxlaWQuYXBwbGUuY29tIiwiYXVkIjoiY29tLnNreW1pbmcuZGV2aWNlbW9uaXRvciIsImV4cCI6MTU2NTY2ODA4NiwiaWF0IjoxNTY1NjY3NDg2LCJzdWIiOiIwMDEyNDcuOTNiM2E3OTlhN2M4NGMwY2I0NmNkMDhmMTAwNzk3ZjIuMDcwNCIsImNfaGFzaCI6Ik9oMmFtOWVNTldWWTNkcTVKbUNsYmciLCJhdXRoX3RpbWUiOjE1NjU2Njc0ODZ9.e-pdwK4iKWErr_Gcpkzo8JNi_MWh7OMnA15FvyOXQxTx0GsXzFT3qE3DmXqAar96nx3EqsHI1Qgquqt2ogyj-lLijK_46ifckdqPjncTEGzVWkNTX8uhY7M867B6aUnmR7u-cf2HsmhXrvgsJLGp2TzCI3oTp-kskBOeCPMyTxzNURuYe8zabBlUy6FDNIPeZwZXZqU0Fr3riv2k1NkGx5MqFdUq3z5mNfmWbIAuU64Z3yKhaqwGd2tey1Xxs4hHa786OeYFF3n7G5h-4kQ4lf163G6I5BU0etCRSYVKqjq-OL-8z8dHNqvTJtAYanB3OHNWCHevJFHJ2nWOTT3sbw// header 解码
{"kid":"AIDOPK1","alg":"RS256"} 其中kid对应上文说的密钥id// claims 解码
{
"iss":"https://appleid.apple.com",
"aud":"com.skyming.devicemonitor",
"exp":1565668086,"iat":1565667486,
"sub":"001247.93b3a799a7c84c0cb46cd08f100797f2.0704",
"c_hash":"Oh2am9eMNWVY3dq5JmClbg",
"auth_time":1565667486
}其中 iss标识是苹果签发的,aud是接收者的APP ID,该token的有效期是10分钟,sub就是用户的唯一标识

如何验证?

首先通过identityToken中的header中的kid,然后结合苹果获取公钥的接口,拿到相应的n和e的值,然后通过下面这个方法构建RSA公钥public RSAPublicKeySpec build(String n, String e) {  BigInteger modulus = new BigInteger(1, Base64.decodeBase64(n));BigInteger publicExponent = new BigInteger(1, Base64.decodeBase64(e));return new RSAPublicKeySpec(modulus, publicExponent);
}通过下面这个方法验证JWT的有效性
public int 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 GlobalCode.SUCCESS;            }           return GlobalCode.THIRD_AUTH_CODE_INVALID;} catch (ExpiredJwtException e) { log.error("apple identityToken expired", e);return GlobalCode.THIRD_AUTH_CODE_INVALID;} catch (Exception e) {log.error("apple identityToken illegal", e);return GlobalCode.FAIL_ILLEGAL_REQ;}
}使用的JWT工具库为:
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version>
</dependency>

2、基于授权码的后端验证

  • 首先需要了解如何构建client_secret,详细文档可以参考如下两个:
  • https://developer.okta.com/blog/2019/06/04/what-the-heck-is-sign-in-with-apple
  • https://developer.apple.com/documentation/signinwithapplerestapi/generate_and_validate_tokens

首先说下client_secret的构建方法:

先在后台生成授权应用APP ID的密钥KEY文件,然后下载密钥文件格式样例:-----BEGIN PRIVATE KEY-----BASE64编码后的密钥
-----END PRIVATE KEY-----public  byte[] readKey() throws Exception {String temp = "密钥文件中间的编码字符串";return Base64.decodeBase64(temp);
}构建client_secret关键代码:String client_id = "..."; // 被授权的APP ID
Map<String, Object> header = new HashMap<String, Object>();
header.put("kid", "密钥id"); // 参考后台配置
Map<String, Object> claims = new HashMap<String, Object>();
claims.put("iss", "team id"); // 参考后台配置 team id
long now = System.currentTimeMillis() / 1000;
claims.put("iat", now);
claims.put("exp", now + 86400 * 30); // 最长半年,单位秒
claims.put("aud", "https://appleid.apple.com"); // 默认值
claims.put("sub", client_id);
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(readKey());
KeyFactory keyFactory = KeyFactory.getInstance("EC");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
String client_secret = Jwts.builder().setHeader(header).setClaims(claims).signWith(SignatureAlgorithm.ES256, privateKey).compact();

如何验证?

String url = "https://appleid.apple.com/auth/token";
// POST 请求
HttpSynClient client = new HttpSynClient(5000, 5000, 5000, 20);
Map<String, String> form = new HashMap<String, String>();
form.put("client_id", client_id);
form.put("client_secret", client_secret);
form.put("code", code);form.put("grant_type","authorization_code");
form.put("redirect_uri", redirectUrl);
HttpResponse result = client.excutePost(url, form);
System.out.println(result);

返回值样例:

{
"access_token":"a0996b16cfb674c0eb0d29194c880455b.0.nsww.5fi5MVC-i3AVNhddrNg7Qw",
"token_type":"Bearer",
"expires_in":3600,
"refresh_token":"r9ee922f1c8b048208037f78cd7dfc91a.0.nsww.KlV2TeFlTr7YDdZ0KtvEQQ",
"id_token":"eyJraWQiOiJBSURPUEsxIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL2FwcGxlaWQuYXBwbGUuY29tIiwiYXVkIjoiY29tLnNreW1pbmcuYXBwbGVsb2dpbmRlbW8iLCJleHAiOjE1NjU2NjU1OTQsImlhdCI6MTU2NTY2NDk5NCwic3ViIjoiMDAwMjY2LmRiZTg2NWIwYWE3MjRlMWM4ODM5MDIwOWI5YzdkNjk1LjAyNTYiLCJhdF9oYXNoIjoiR0ZmODhlX1ptc0pqQ2VkZzJXem85ZyIsImF1dGhfdGltZSI6MTU2NTY2NDk2M30.J6XFWmbr0a1hkJszAKM2wevJF57yZt-MoyZNI9QF76dHfJvAmFO9_RP9-tz4pN4ua3BuSJpUbwzT2xFD_rBjsNWkU-ZhuSAONdAnCtK2Vbc2AYEH9n7lB2PnOE1mX5HwY-dI9dqS9AdU4S_CjzTGnvFqC9H5pt6LVoCF4N9dFfQnh2w7jQrjTic_JvbgJT5m7vLzRx-eRnlxQIifEsHDbudzi3yg7XC9OL9QBiTyHdCQvRdsyRLrewJT6QZmi6kEWrV9E21WPC6qJMsaIfGik44UgPOnNnjdxKPzxUAa-Lo1HAzvHcAX5i047T01ltqvHbtsJEZxAB6okmwco78JQA"
}

其中id_token是一个JWT,其中claims中的sub就是授权的用户唯一标识,该token也可以使用上述的验证方法进行有效性验证,另外授权code是有时效性的,且使用一次即失效

扩展资料

JWT:https://www.cnblogs.com/softidea/p/7041532.html
ECDSA 椭圆曲线签名,JDK 1.7 的第四个版本提供了对ECDSA的支持:https://blog.csdn.net/qq_35612816/article/details/78904225

Sign in with Apple(苹果授权登陆)相关推荐

  1. Sign in with Apple(苹果授权登陆)服务端验证-测试通过版

    Sign in with Apple(苹果授权登陆)服务端验证-测试通过版 1.先引用2个jwt用到的jar包 2.算法的工具类 三方登录调用验证工具类 苹果登录方式有2种,这里介绍基于JWT算法验证 ...

  2. Sign in with Apple(苹果授权登陆) java jwt方式验证

    本文章借鉴的原文链接:https://blog.csdn.net/wpf199402076118/article/details/99677412 苹果授权登陆方式 PC/M端授权登陆,采用协议类似于 ...

  3. 苹果授权登陆 服务端验证(java)

    需要的jar包: jose4j-0.6.4.jar:jwks-rsa-0.9.0.jar:jjwt-0.9.1.jar: jar包下载地址:https://download.csdn.net/down ...

  4. iOS 苹果授权登录(Sign in with Apple)

    在 iOS13 中,如果 App 提供第三方登录,就必须添加 苹果登录 Sign in with Apple 选项,并要求所有开发者于 2020年4月之前 完成现有应用的更新,否则审核不给通过. iO ...

  5. sign in with Apple,使用Apple授权登录

    软件环境:Xcode 11.4.iOS13+ 创建时间:2020年 03月15号 更新时间:2021年 03月02号 这篇文章都说了什么 使用Apple登录的注意事项 接入原理概览 客户端编码 审核规 ...

  6. 苹果登录 Sign In with Apple

    <?php /*** Sign in with Apple 示例* composer安装: composer require griffinledingham/php-apple-signin* ...

  7. Sign in with Apple REST API / Revoke tokens (JAVA)

    Sign in with Apple REST API / Revoke tokens (JAVA) 前言 由于Apple政策, Apple ID登录的用户注销时需要进行Revoke Token. 顺 ...

  8. iOS开发:使用 Sign In With Apple(登录)用法以及注意事项

    一.为什么要使用Sign in with Apple? 苹果在19年 9 月12 号更新了审核指南,加入 4.8 Sign in with Apple 一条,要求所有使用第三方登录 的 App,都必须 ...

  9. 关于Sign in with Apple (Apple 登录) PHP的后端验证

    1. 首先阅读官网文档 https://developer.apple.com/documentation/signinwithapplerestapi 重点讲解苹果授权登陆 后端PHP如何验证 1. ...

最新文章

  1. ZOUNDRY TEST
  2. Flash Catalyst之乱盖
  3. kali入侵windows
  4. java邻接表无向图的创建_邻接表无向图(三) 之Java详解
  5. pcie协议_PCIE总线,你不得不知道的信号分布及使用情况
  6. 路由器下交换机下计算机不能共享,路由器下接交换机,路由下的电脑和交换机下的电脑如何实现打印机共享?...
  7. 表达式求值Spring.Expressions
  8. 瑞幸咖啡股价再大涨超36% 目前总市值约13.87亿美元
  9. 自动操作电脑的软件_技术干货 | 自动透镜植入定位仪
  10. css光盘转动,CSS 实现加载动画之五-光盘旋转
  11. python和c 的区别-python和c语言的主要区别总结
  12. 解决办法:用户名不在 sudoers文件中 此事将被报告
  13. 数据结构(C语言版)
  14. Axure绘制页面框架 图文详解教程
  15. 移动端 H5 概念术语(一)
  16. python爬取网易云评论最多的歌_python爬取网易云音乐评论
  17. SM敏捷实践经验总结
  18. 手机当作电脑无线摄像头
  19. HarmonyOS报名选择应用,HarmonyOS应用开发系列课,华为内部官方培训来袭!
  20. Java中boolean型变量的默认值问题

热门文章

  1. 从0到1亿,招商银行App用户增长的“道”与“术”
  2. Mac 与 Linux Windows 常见使用区别
  3. 纺织服装行业通过GRS认证增加产品竞争力
  4. GEE注册详细指南,第二次注册,亲测成功.
  5. java 写一个简易闹钟
  6. IOS面试题目(稍微深度型)
  7. System.Security.SecurityException Failed to negotiate HTTPS connection with server.fiddler.network
  8. 工业4.0下IOT融合技术核心OT节点
  9. application.yml中定义数组的两种方式
  10. 国人之光-分布式存储框架FastDFS入门篇