最近在套第三方Web AppleId登入遇到了一點眉角,在這邊紀錄一下
Apple developer設定
在 Certificates, Identifiers & Profiles -> Identifiers -> Service IDs
按旁邊 + 號,選擇 Service ID 來創建您的 Service ID這裡有二個選項要填:
Description這裏填入您網站的名字(注意:這個值會顯示在前台網站給使用者看到)
Identifier你可以隨意取一個,作為辨識用勾選 Sign in with Apple 並按旁邊的 Configure
Sign Key 驗證金鑰
我們需要建立一個 Sign Key 在等一下跟蘋果 API 做驗證使用,這部分因為網站跟 App 驗證流程後半段是一樣的,不管支援哪一個部分都要做。
在 Certificates, Identifiers & Profiles -> Keys 按旁邊 + 號,建立一個 Key
Key name可以自行取名,勾選 Sign in with Apple 並按旁邊的 Configure
Primary App ID選擇主要 App 使用的 App ID
Grouped App IDs取名會把網站跟 App 群組綁在一起,按下 Continue 之後會讓你下載一個私鑰 p8 檔案,注意這只能被下載一次,請好好保存。如果不見的話就只能再重新產生一個。
以上設定完之後,開始實作登入,Apple有一份Web登入的文件
Apple登入的網址
https://appleid.apple.com/auth/authorize?client_id={0}&redirect_uri={1}&response_type=code&scope=openid%20email%20name&response_mode=form_post&state={2}
client_id
它可以是 App ID (也就是 Bundle ID) 也可以是 Service ID。
如果要 網站端做登入,它就會是 Service ID。
redirect_uri
OAuth 之後要轉跳的網址
Certificates, Identifiers & Profiles -> Identifiers -> Service IDs -> 您的 Service ID -> Configure -> Return URLs
state
一個您設定的,辨識用的字串
scope
我都填固定值 name email (注意:中間有空格要加入%20)
以上參數組好之後,可以直接連結會出現Apple登入畫面,登入完成後他會Post到你指定的redirect_uri,這邊注意一下他是Post不是Get喔,Facebook跟Line都是使用Get的!!
Apple CallBack處理
scope
我都填固定值 name email (注意:中間有空格要加入%20)
code
有效期為五分鐘的一次性授權碼
user
id_token
error
返回的錯誤碼
Call Token API
使用code呼叫另一個Token API取得相關資料
Token API文件
https://developer.apple.com/documentation/sign_in_with_apple/generate_and_validate_tokens
如文件所示需帶入的參數為client_id、client_secret、code、grant_type、refresh_token、redirect_uri
client_id
如果要 網站端做登入,它就會是 Service ID
code
就是CallBack回來的code參數
grant_type
這裡我們填 authorization_code 來交換 AccessToken
refresh_token
這個不用給
redirect_uri
OAuth 之後要轉跳的網址
client_secret
一個 JWT 格式的要求文件,並利用前面申請的 Sign Key 來簽章
這邊最難的就是取client_secret,取這個需要幾個關鍵參數
TeamId
你的開發者帳號 Team ID,這可以在你的右上角看到
進去 Certificates, Identifiers & Profiles -> Identifiers -> App IDs -> 您的 App -> App ID Prefix 可以看見
KeyId
您建立驗證的 Sign Key 的 Key ID
在 Certificates, Identifiers & Profiles -> Keys -> 您的 Apple Sign Key -> View Key Details -> Key ID 可以看到
PriveKey
從Keys頁面下載,只能下載一次,請好好保存
下載之後會有PriveKey,以上相關參數放入下面的c#方法,使用GetClientSecret取得client_secret
private string GetClientSecret(){ var signatureAlgorithm = GetEllipticCurveAlgorithm(_config.PriveKey); ECDsaSecurityKey eCDsaSecurityKey = new ECDsaSecurityKey(signatureAlgorithm) { KeyId = _config.KeyId }; var handler = new JwtSecurityTokenHandler(); var subject = new Claim("sub", _config.ClientId);//需要IOS提供 JwtSecurityToken token = handler.CreateJwtSecurityToken( issuer: _config.TeamId, audience: "https://appleid.apple.com", expires: DateTime.UtcNow.AddMinutes(5), issuedAt: DateTime.UtcNow, notBefore: DateTime.UtcNow, subject: new ClaimsIdentity(new[] { subject }), signingCredentials: new SigningCredentials(eCDsaSecurityKey, SecurityAlgorithms.EcdsaSha256)); return token.RawData; } private ECDsa GetEllipticCurveAlgorithm(string privateKey) { var keyParams = (ECPrivateKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKey)); var normalizedEcPoint = keyParams.Parameters.G.Multiply(keyParams.D).Normalize(); return ECDsa.Create(new ECParameters { Curve = ECCurve.CreateFromValue(keyParams.PublicKeyParamSet.Id), D = keyParams.D.ToByteArrayUnsigned(), Q = { X = normalizedEcPoint.XCoord.GetEncoded(), Y = normalizedEcPoint.YCoord.GetEncoded() } }); }
相關參數組好之後在Post到Token API就會取得id_token
id_token是一個JWT,用base64UrlDecode解開之後Payload,sub就是openId
{ "iss": "https://appleid.apple.com", "aud": "com.your.app.id", "exp": 1596621649, "iat": 1596621049, "sub": "001451.3dc436155xxxxxxxxxxxxxxxxxxxx59f.0447", "c_hash": "iUqI9Vyxxxxxxxxxg-CyoA", "email": "8m2xxxxmew@privaterelay.appleid.com", "email_verified": "true", "is_private_email": "true", "auth_time": 1596621049, "nonce_supported": true }
參考文件
https://blog.jks.coffee/sign-in-with-apple/
https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_js/incorporating_sign_in_with_apple_into_other_platforms
https://blog.csdn.net/Anlan2010/article/details/108419737