iOS 13 蘋果帳號登錄與後臺驗證相關

簡介

在WWDC 2019,蘋果推出了Sign In with Apple這一iOS 13的新特性,用戶能夠直接利用蘋果ID登錄應用,免去了輸入郵箱、密碼,驗證登錄郵箱等繁瑣的步驟。同時Sign In with Apple提供了跨平臺特性和安全性的提升。ios

另外一方面它也提出了新的審覈要求,在新的要求中提到但凡包含了第三方登陸的應用,則一樣須要適配Sign In with Apple,不然會有審覈風險:git

Sign In with Apple will be available for beta testing this summer. It will be required as an option for users in apps that support third-party sign-in when it is commercially available later this year.github

另外使用Sign In with Apple須要用戶開啓了兩步認證,若是沒有開啓則會在第一次使用時提示開啓,不開啓將沒法使用web

如何接入 Sign In with Apple

1. 項目配置

添加Sign in with Applecapability算法

並在項目中加入AuthenticationServices.framework便可。當須要使用時,須要在文件中添加<AuthenticationServices/AuthenticationServices.h>引用。api

2. 添加內置的登陸按鈕

登陸按鈕可使用蘋果推薦的按鈕ASAuthorizationAppleIDButton,具體的設計樣式能夠參看這裏,大體的樣式以下:數組

注意:安全

  • 內置的登陸按鈕須要放在顯眼的位置,沒有強調必定要放在首位,可是提出不能讓用戶滾動後纔看到這一個按鈕。
  • 內置的登陸按鈕的大小和圓角是能夠自行調整的,可是大小有最大和最小的限制。
  • 沒有強調必定要使用內置的登錄按鈕,可是在設計指南上指出最好使用樣式相近的設計。

處理登陸事件

3.1 建立請求

3.1.1 新用戶登陸

在新用戶點擊內置的登陸按鈕,指望使用蘋果ID進行註冊和登陸時,咱們須要使用ASAuthorizationAppleIDProvider來建立一個ASAuthorizationAppleIDRequest請求,在這個請求中,咱們能夠配置一個ASAuthorizationScope數組,來規定須要用戶提供什麼樣的信息,目前ASAuthorizationScope僅包含兩個:bash

  • ASAuthorizationScopeEmail: 須要用戶提供電子郵件地址
  • ASAuthorizationScopeFullName: 須要用戶提供姓名

須要注意的是,須要提供電子郵件時,用戶是能夠選擇隱藏真實的郵件地址,這樣獲取到的郵件地址是這樣的:服務器

r45N934br1@privaterelay.appleid.com

該郵箱收到的郵件會轉發到用戶真實的郵箱上。另外須要提供姓名時,用戶是能夠對姓名進行修改的,並且是任意修改。

在用戶填寫完姓名與選擇是否隱藏郵箱後,便可以輸入蘋果ID的密碼,並自動完成註冊過程,若是無網絡會沒法繼續,停留在在這個頁面

代碼實例:

// 建立請求

ASAuthorizationAppleIDProvider *appleIDProvider = [ASAuthorizationAppleIDProvider new];
ASAuthorizationAppleIDRequest *request = appleIDProvider.createRequest;
[request setRequestedScopes:@[ASAuthorizationScopeFullName,ASAuthorizationScopeEmail]];
    
複製代碼

3.1.2 舊用戶登陸

若是咱們的APP用戶以前已經登錄過,而且在keyChain上保存了用戶名和密碼時,能夠同時使用ASAuthorizationAppleIDProviderASAuthorizationPasswordProvider來建立請求

這種方式是針對用戶已經使用帳號密碼登陸過該app,而且已經將他們保存到keyChain中的狀況,因爲對我如今項目目前的狀態來講意義不大,因此不在本文進行討論。

3.2 發起請求

發起請求須要用到ASAuthorizationController,它能夠同時發起多個Provider的請求。

代碼實例:

// 發起請求

ASAuthorizationController *controller = [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[request]];
controller.delegate = self;
controller.presentationContextProvider = self;
[controller performRequests];

複製代碼

在發起請求後就會出現Sign In with Apple的UI,在用戶完成了登陸等操做後會返回請求結果由咱們app進行處理。

3.3 處理請求結果

ASAuthorizationController在其中提供了ASAuthorizationControllerDelegate代理,用於請求結果的回調,代理提供了兩個代理方法:

成功回調:

    • (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization

失敗回調

    • (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithError:(NSError *)error

在成功的回調中,咱們可以獲取一個ASAuthorization對象,這個對象有providercredential這兩個屬性,其中provider屬性可以讓咱們知道是哪一類的Provider發起的請求,而credential則是蘋果帳號登陸結果的一個認證。

在「新用戶登陸」的狀況下,返回的credentialASAuthorizationAppleIDCredential,而「舊用戶登陸」的狀況下,則返回ASPasswordCredential

咱們側重於ASAuthorizationAppleIDCredential屬性的解析:

  • User ID: 蘋果用戶惟一標識符,它在同一個開發者帳號下的全部 App 下是同樣的,咱們能夠用它來與後臺的帳號體系綁定起來(相似於微信的OpenID)。
  • Verification Data: 包括identityToken, authorizationCode。用於傳給開發者後臺服務器,而後開發者服務器再向蘋果的身份驗證服務端驗證本次受權登陸請求數據的有效性和真實性。
  • Account Information: Name, verified email,蘋果用戶信息,包括全名、郵箱等。
  • Real User Indicator: 用於判斷當前登陸的蘋果帳號是不是一個真實用戶,取值有:unsupportedunknownlikelyReal

代碼實例:

- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization {
		//Sign with Apple 成功
		if ([authorization.credential isKindOfClass:[ASAuthorizationAppleIDCredential class]]) {
    		//此時爲使用Sign With Apple 方式登陸
  			
			ASAuthorizationAppleIDCredential *credential = authorization.credential;
  			NSString *userID = credential.user;
  			NSString *fullname = credential.fullName;
  			NSData *token = credential.identityToken
  			
  			//繼續進行客戶端後臺登陸驗證
    }
}
複製代碼

3.4 與服務器驗證數據

時序圖

總體流程與普通的第三方登陸十分類似,一樣須要獲取用戶ID與token,交給後臺驗證本次登陸的有效性。

驗證流程相關

  1. 步驟1與2在客戶端內完成,客戶端選擇使用ASAuthorizationAppleIDProvider來完成登陸,若是登陸成功,蘋果將會返回以下數據:
  • User ID: 蘋果用戶惟一標識符,它在同一個開發者帳號下的全部 App 下是同樣的,咱們能夠用它來與後臺的帳號體系綁定起來(相似於微信的OpenID)。
  • Verification Data: 包括identityToken, authorizationCode。用於傳給開發者後臺服務器,而後開發者服務器再向蘋果的身份驗證服務端驗證本次受權登陸請求數據的有效性和真實性。
  • Account Information: 蘋果用戶信息,包括全名、郵箱等,登陸時用戶能夠選擇隱藏真實的郵件地址和隨意修改姓名。
  • Real User Indicator: 用於判斷當前登陸的蘋果帳號是不是一個真實用戶,取值有:unsupportedunknownlikelyReal
  1. 步驟3與4中,客戶端會把identityToken, authorizationCode, userID這三個參數傳給服務器,用於驗證本次登陸的有效性。

其中identityToken是一個通過簽名的JSON Web Token(JWT),它包含了:

它分爲了三個部分:

  • header: 包括了key id 與加密算法
  • payload:
    • iss: 簽發機構,蘋果
    • aud: 接收者,目標app
    • exp: 過時時間
    • iat: 簽發時間
    • sub: 用戶id
    • c_hash: 一個哈希數列,做用未知
    • auth_time: 簽名時間
  • signature: 用於驗證JWT的簽名

服務端在獲取客戶端發出的identityToken後,須要進行以下步驟:

  1. 須要逆向構造過程,decode出JWT的三個部分
  2. appleid.apple.com/auth/keys中獲取公鑰,並將公鑰轉換pem對JWT進行驗證
  3. identityToken經過驗證,則能夠根據其payload中的內容進行驗證等操做

token驗證原理:

由於idnetityToken使用非對稱加密 RSASSA【RSA簽名算法】 和 ECDSA【橢圓曲線數據簽名算法】,當驗證簽名的時候,利用公鑰來解密Singature,當解密內容與base64UrlEncode(header) + "." + base64UrlEncode(payload)的內容徹底同樣的時候,表示驗證經過。

防止中間人攻擊原理:

該token是蘋果利用私鑰生成的一段JWT,並給出公鑰咱們對token進行驗證,因爲中間人並無蘋果的私鑰,因此它生成出來的token是沒有辦法利用蘋果給出的公鑰進行驗證的,確保的token的安全性。

4. 處理 Apple ID 登陸狀態變化

用戶利用Apple ID進行登陸,因此應該對ID退出登陸等狀況進行處理。另外用戶在利用Apple ID登陸後,能夠在設置頁面刪除曾經登陸過的應用,相似於解除綁定的操做,這時應用也須要作對應處理。

蘋果提供了一個快速的API來讓咱們查詢用戶的Apple ID狀態:

- [ASAuthorizationAppleIDProvider getCredentialStateForUserID:completion:]
複製代碼

這個接口利用在登陸時獲取的userID,可以快速返回賬號狀態:

  • authorized: 已認證
  • notFound: 用戶可能還沒有將賬號與Apple ID綁定
  • revoked: 帳號已經註銷

這個方法應該在啓動時與應用返回前臺時調用,確保帳號狀態可以及時更新。

總結

  • 做爲一種相似於三方登陸的登陸方式,後臺方面須要關注的是登陸狀態的驗證帳號和apple userID綁定的邏輯。
  • 蘋果帳號切換、註銷等狀態會在客戶端內處理,並在狀態發生變化時登出賬號。

另外蘋果在與後臺驗證一塊的文檔過於語焉不詳,web端與app端的驗證流程也有十分大的區別,讓人頭大。

更多內容能夠關注個人博客

參考文檔

相關文章
相關標籤/搜索