apple帐号登录服务器端接入
原文转载自http://cwqqq.com/2020/09/27/apple_login_api_server_sideapple帐号登录服务器端接入最近有新产品要提交App Store,发现APP审核增加了接入apple帐号登录的要求。所以,借此机会研究下apple帐号登录,做一个分享。Sign In With Apple这是苹果推出一套标准接口,用户通过端上的Apple ID登录第三方APP。
新博客地址(shankusu.me)
原文转载自
http://cwqqq.com/2020/09/27/apple_login_api_server_side
apple帐号登录服务器端接入
最近有新产品要提交App Store,发现APP审核增加了接入apple帐号登录的要求。所以,借此机会研究下apple帐号登录,做一个分享。
Sign In With Apple
这是苹果推出一套标准接口,用户通过端上的Apple ID登录第三方APP。官方网址 https://developer.apple.com/documentation/sign_in_with_apple
时序图如下:
接入过程分两步:
1、客户端拉起用户登陆,获取授权码及用户信息
2、服务端验证
客户端拉起apple授权页面,等用户授权登录后,可以取到用户的 authorizationCode 、 identityToken 、user 等。
客户端的请求结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
这些信息具体含义和用途:
∙ 用户ID: user,苹果用户唯一标识,该值在同一个开发者账号下的所有 App 下是一样的。
∙ 验证数据: identityToken , authorizationCode ,用于服务端验证授权请求的合法性。
∙ 用户信息: fullName , email,包括全名、邮箱等。
∙ 真实用户标志: realUserStatus ,用于判断当前账号是否是一个真实用户,取值有:unsupported、unknown、likelyReal。
其实,根据 identityToken ,解析后可以得到用户信息。但是,数据从客户端取到,然后转发给服务端,这个过程中,数据存在被修改的可能性。
有两种验证用户的方法:
1、 解析出用户数据,再利用 Apple 公钥验证 identityToken
2、 根据 authorizationCode 从 Apple ID server 重新拿到 identityToken, 再解析出用户数据
当然,方法2拿到的 identityToken 也可以用公钥验证
解析验证 identity Token
从网上找了一个苹果服务器返回的 identityToken ,数据如下:
eyJraWQiOiI4NkQ4OEtmIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL2FwcGxlaWQuYXBwbGUuY29tIiwiYXVkIjoiY29tLmNoYW5nZGFvLnR0c2Nob29sIiwiZXhwIjoxNTg5MTg1Mjg1LCJpYXQiOjE1ODkxODQ2ODUsInN1YiI6IjAwMTk0MC43YTExNDFhYTAwMWM0NjllYTE1NjNjNmJhZTk5YzM3ZC4wMzA3IiwiY19oYXNoIjoiN1gzc2x2dHVBU0kwYmFSbU0wVGFrQSIsImVtYWlsIjoiYXEzMmsydnpjd0Bwcml2YXRlcmVsYXkuYXBwbGVpZC5jb20iLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJpc19wcml2YXRlX2VtYWlsIjoidHJ1ZSIsImF1dGhfdGltZSI6MTU4OTE4NDY4NSwibm9uY2Vfc3VwcG9ydGVkIjp0cnVlfQ.S9wCOt6EeOoRrSMq4kUkPgJPyP1ruMXEcEZeeQEd1CDpcyVWLI8nTOqrl-l0sWYR-5nl2-1iJyiu77fRv8T7dBoV0EHT7GgM1l7qhnWsI9I8V-56rA9ArdJrLIBJbxu7j-xzQhZb6PZ5MSxPZ6WqZay0RpP9JiQ23ybssWQsMnqzvVZkye0iNtBGT1LnfT80XNxmj8L2uJZY08mXjjWWsYY_h0_IRvqOLyaW99w-F8T9KuDkWz2Z-DJX_tiKC0DOT03ypBv82H0v_v-8lFlp4rNRSB82CdgfYwEWElU7zKZfaHJOxT3wOvRXNpbj6_hENPdbtG2ozgdg2oVEiamz0g |
这是一个 JWT 数据串,先说下公钥验证的方法。
首先,要取到苹果的公钥,公钥目前是以 JWK 的形式对外发布,需要自己转成pem,获取的URL为 https://appleid.apple.com/auth/keys,数据如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
实际上,这里是两个JWK数据,我们需要转成对应的证书pem文件。
字段的含义如下:
alg | The encryption algorithm used to encrypt the token. |
e | The exponent value for the RSA public key. |
kid | A 10-character identifier key, obtained from your developer account. |
kty | The key type parameter setting. This must be set to “RSA”. |
n | The modulus value for the RSA public key. |
use | The intended use for the public key. |
其中,e、n以及kid使用了大端字节序表示,再通过base64url编码
这里,我封装了JWK转pem的方法(目前只支持 RSA公钥,以后看需要拓展。)
RSA公钥需要 n、e字段,接口如下:
1 2 3 4 |
|
执行结果如下:
1 2 3 4 5 6 7 8 9 10 |
|
然后,利用公钥 pem 验证 identityToken(利用第三方库libjwt实现),方法如下
1 2 3 4 |
|
执行结果如下:
1 2 |
|
如果不想公钥验证,直接解析 identityToken的方法如下
1 2 3 4 |
|
执行结果如下:
1 2 |
|
说下这几个字段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
aud为app id,也就是请求的client_id, sub为用户在该app下的唯一id, iat为token的创建时间,exp为token的有效期,email为邮箱地址,其他字段的含义可以看这里
另外,说下c_hash, at_hash, s_hash:
c_hash : code 的hash值
at_hash : access_token 的hash值
s_hash : state 的hash值
我没有做过验证,在apple官网没有找到答案。网上找到OAuth 2.0开放协议对这块有说明 https://openid.net/specs/openid-connect-core-1_0.html#TokenSubstitution
1 2 3 4 5 |
|
服务端获取 identity Token
利用 authorizationCode 获取 identityToken 的方法:(官方文档 https//developer.apple.com/documentation/sign_in_with_apple/generate_and_validate_tokens)
验证的过程是HTTPS验证,API如下:
POST https://appleid.apple.com/auth/token
请求字段说明:
client_id:这个是app id
client_secret: 密钥信息,使用 JWT编码,详见后文
code: 授权码,传客户端取到的 authorizationCode
grant_type: 此时固定写 authorization_code
其他非必要字段,就不做说明。
其中,需要特别讲下 client_secret,是一个json数据,例子如下:
1 2 3 4 5 6 7 8 9 10 11 |
|
其中,iss为team id,iat为当前时间戳,exp为失效时间戳,aud固定,sub为app包名; kid为开发者帐号后台申请private key时系统附带生成的key id,猜测是apple用以确定解密对应的public key
这个字段需要使用 JWT 编码,转成 JWT数据串。
这里,我封装了jwt,如下:
1 2 |
|
JWT是一个基于JSON结构化的编码标准(RFC 7519),它定义了一种紧凑的、自包含的方式,可在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。(jwt.io可获取实现算法)
JWT由三部分组成,之间用圆点(.)连接。这三部分分别是:Header.Payload.Signature
Header | 头部域,使用Base64编码,会消除等号 | { “alg”: “HS256”, “typ”: “JWT” } |
Payload | 数据域,使用 Base64编码,会消除等号 | { “sub”: “1234567890”, “name”: “John Doe”, “iat”: 1516239022 } |
Signature | 签名,对Header.Payload进行签名,支持多种算法 |
优点:支持多种签名算法,可兼顾安全性和效率,避免数据伪造
缺点:数据都是使用base64_encode简单编码,不能传输敏感信息。
需要注意的是,验证接口 /auth/token 返回的数据,字段如下:
access_token | (Reserved for future use) A token used to access allowed data. Currently, no data set has been defined for access. |
expires_in | The amount of time, in seconds, before the access token expires. |
id_token | A JSON Web Token that contains the user’s identity information. |
refresh_token | The refresh token used to regenerate new access tokens. Store this token securely on your server. |
token_type | The type of access token. It will always be bearer. |
关键字段 id_token,就是前面提到的 identity Token, 即用户信息,同样使用jwt编码,参照上文解开。
最后语
文章到这里就结束了,最后分享文中提到的 lua jwt库, 地址 https://github.com/chenweiqi/lua_jwt
主要逻辑是c开发的,lua只是实现扩展,有遇到bug喊我!
更多推荐
所有评论(0)