iOS實(shí)現(xiàn)蘋果第三方登錄功能2020-03-18

Sign In with Apple 讓用戶可以使用面容 ID 或觸控 ID 來輕松進(jìn)行身份認(rèn)證,而內(nèi)置的雙重認(rèn)證則再增添一層安全保障

1.實(shí)現(xiàn)

實(shí)現(xiàn)分四大部分:

1郑气、創(chuàng)建Sign in? ? with Apple Button.

2腰池、跟用戶提出授權(quán)請求.

3示弓、根據(jù)用戶的授權(quán)來驗(yàn)證用戶.

4、處理用戶授權(quán)變更.


2.開啟 Sign in with Apple 功能

登錄開發(fā)者網(wǎng)站跨跨,在需要添加 Sign in with Apple 功能的 Identifier 開啟功能歹叮。

1.登陸developer賬號,在app bundle ID的Capabilities里德谅,打勾Sign In with Apple



2.在Xcode(Xcode 11.0 Beta或更新版本)的工程里面 Signing & Capabilities 開啟Sign in with Apple 功能窄做。

3.代碼集成

3.1創(chuàng)建登錄按鈕

官方提供了一個 ASAuthorizationAppleIDButton (繼承自UIControl)椭盏,使用這個來創(chuàng)建一個登錄按鈕吻商。

Apple 提供的登錄按鈕有三種外觀:白色艾帐,帶有黑色輪廓線的白色和黑色。? 文案有兩種:Sign In

with Apple 和 Continue with Apple准浴。(具體使用哪個文案捎稚,根據(jù)自身業(yè)務(wù)需求來定)另外今野,按鈕寬高默認(rèn)值為 {width:130, height:30}。

對于 ASAuthorizationAppleIDButton 我們能夠自定義的東西比較少匾南,比如背景色不能更改蛔外,文案只有兩種可選夹厌,并且值不能修改,可以調(diào)整的只有圓角cornerRadius和size 臂聋。

3.2Authorization 發(fā)起授權(quán)登錄請求

- (void)signInWithApple API_AVAILABLE(ios(13.0))

{

???ASAuthorizationAppleIDProvider *provider =[[ASAuthorizationAppleIDProvider alloc] init];

???ASAuthorizationAppleIDRequest *request = [provider createRequest];

???request.requestedScopes = @[ASAuthorizationScopeFullName,ASAuthorizationScopeEmail];


???ASAuthorizationController *vc = [[ASAuthorizationController alloc]initWithAuthorizationRequests:@[request]];

??? vc.delegate =self;// 會提供請求后的結(jié)果回調(diào)孩等,比如用戶請求失敗,或者用戶請求成功冰垄。

???vc.presentationContextProvider = self;// 是為驗(yàn)證的用戶界面提供所需的window

??? [vcperformRequests];

}

3.3授權(quán)回調(diào)處理來驗(yàn)證用戶

下面是 ASAuthorizationControllerDelegate 方法虹茶,一個是授權(quán)成功的回調(diào)隅要,一個是失敗的回調(diào)步清。

#pragma mark - ASAuthorizationControllerDelegate


- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(ios(13.0))

{

??? if ([authorization.credential isKindOfClass:[ASAuthorizationAppleIDCredential class]])?????? {

??????? ASAuthorizationAppleIDCredential*credential = authorization.credential;


????????NSString*state = credential.state;

??????? NSString*userID = credential.user;

??????? NSPersonNameComponents*fullName = credential.fullName;

??????? NSString*email = credential.email;

??????? NSString*authorizationCode = [[NSString alloc] initWithData:credential.authorizationCode encoding:NSUTF8StringEncoding]; // refresh token

??????? NSString*identityToken = [[NSString alloc] initWithData:credential.identityToken encoding:NSUTF8StringEncoding]; // access token

??????? ASUserDetectionStatus realUserStatus= credential.realUserStatus;


????????NSLog(@"state: %@", state);

??????? NSLog(@"userID: %@", userID);

??????? NSLog(@"fullName: %@", fullName);

??????? NSLog(@"email: %@", email);

??????? NSLog(@"authorizationCode: %@", authorizationCode);

??????? NSLog(@"identityToken: %@", identityToken);

??????? NSLog(@"realUserStatus: %@", @(realUserStatus));

??? }

}

//當(dāng)我們授權(quán)成功后廓啊,我們可以在 authorizationController:didCompleteWithAuthorization: 這個代理方法中獲取到ASAuthorizationAppleIDCredential 崖瞭,通過這個可以拿到用戶的 userID撑毛、email、fullName雌续、authorizationCode驯杜、identityToken 以及 realUserStatus 等信息做个。


- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithError:(NSError *)error API_AVAILABLE(ios(13.0))

{

??? NSString*errorMsg = nil;

??? switch (error.code) {

??????? case ASAuthorizationErrorCanceled:

??????????? errorMsg= @"用戶取消了授權(quán)請求";

??????????? break;

??????? case ASAuthorizationErrorFailed:

??????????? errorMsg= @"授權(quán)請求失敗";

??????????? break;

??????? case ASAuthorizationErrorInvalidResponse:

??????????? errorMsg= @"授權(quán)請求響應(yīng)無效";

??????????? break;

??????? case ASAuthorizationErrorNotHandled:

??????????? errorMsg= @"未能處理授權(quán)請求";

??????????? break;

??????? case ASAuthorizationErrorUnknown:

???????? ???errorMsg= @"授權(quán)請求失敗未知原因";

??????????? break;

??? }

??? NSLog(@"%@", errorMsg);

}

這些信息具體含義和用途:

? User ID: Unique, stable, team-scoped user ID居暖,蘋果用戶唯一標(biāo)識符太闺,該值在同一個開發(fā)者賬號下的所有 App 下是一樣的,開發(fā)者可以用該唯一標(biāo)識符與自己后臺系統(tǒng)的賬號體系綁定起來蟀淮。

? Verification data: Identity token, code,驗(yàn)證數(shù)據(jù)涨缚,用于傳給開發(fā)者后臺服務(wù)器仗岖,然后開發(fā)者服務(wù)器再向蘋果的身份驗(yàn)證服務(wù)端驗(yàn)證本次授權(quán)登錄請求數(shù)據(jù)的有效性和真實(shí)性览妖,詳見 Sign In with Apple REST API讽膏。如果驗(yàn)證成功,可以根據(jù)userIdentifier 判斷賬號是否已存在俐末,若存在奄侠,則返回自己賬號系統(tǒng)的登錄態(tài)垄潮,若不存在,則創(chuàng)建一個新的賬號旅急,并返回對應(yīng)的登錄態(tài)給 App牡整。

? Account information: Name, verified email逃贝,蘋果用戶信息,包括全名潦闲、郵箱等歉闰。

? Real user indicator: High confidence indicator that

likely real user,用于判斷當(dāng)前登錄的蘋果賬號是否是一個真實(shí)用戶凹炸,取值有:unsupported昼弟、unknown舱痘、likelyReal。

失敗情況會走 authorizationController:didCompleteWithError: 這個方法塌碌,具體看代碼吧旬盯。

[if !supportLists]3.4.? [endif]處理用戶授權(quán)變更

通過上面的步驟一個完整的授權(quán),已經(jīng)完成接剩。BUT懊缺,我們還需要處理一些 Case培他。

? 用戶終止 App 中使用 Sign in with Apple 功能

? 用戶在設(shè)置里注銷了AppleId

這些情況下靶壮,App 需要獲取到這些狀態(tài)员萍,然后做退出登錄操作碎绎,或者重新登錄。我們需要在 App 啟動的時候奸晴,通過 getCredentialState:completion: 來獲取當(dāng)前用戶的授權(quán)狀態(tài)寄啼。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {


????if (@available(iOS 13.0, *)) {

??????? NSString*userIdentifier = 鑰匙串中取出的 userIdentifier;

??????? if (userIdentifier) {

??????????? ASAuthorizationAppleIDProvider*appleIDProvider = [ASAuthorizationAppleIDProvider new];

??????????? [appleIDProvider getCredentialStateForUserID:userIdentifier

????????????????????????????????????????????? completion:^(ASAuthorizationAppleIDProviderCredentialState credentialState,

????????????????????????????????????????????????????????? ?NSError* _Nullable error)

??????????? {

??????????????? switch (credentialState) {

??????????????????? case ASAuthorizationAppleIDProviderCredentialAuthorized:

??????????????????????? // The Apple ID credential is valid

??????????????????????? break;

??????????????????? case ASAuthorizationAppleIDProviderCredentialRevoked:

??????????????????????? // Apple ID Credential revoked, handle unlink

??????????????????????? break;

??????????????????? case ASAuthorizationAppleIDProviderCredentialNotFound:

??????????????????????? // Credential not found, show login UI

??????????????????????? break;

??????????????? }

??????????? }];

??????? }

??? }


????return YES;

}

ASAuthorizationAppleIDProviderCredentialState 解析如下:?ASAuthorizationAppleIDProviderCredentialAuthorized授權(quán)狀態(tài)有效墩划;?ASAuthorizationAppleIDProviderCredentialRevoked上次使用蘋果賬號登錄的憑據(jù)已被移除乙帮,需解除綁定并重新引導(dǎo)用戶使用蘋果登錄;?ASAuthorizationAppleIDProviderCredentialNotFound未登錄授權(quán)驾茴,直接彈出登錄頁面锈至,引導(dǎo)用戶登錄异吻。

另外诀浪,在 App 使用過程中,你還可以通過通知方法來監(jiān)聽 revoked 狀態(tài)睛竣,可以添加 ASAuthorizationAppleIDProviderCredentialRevokedNotification 這個通知射沟,收到這個通知的時候与境,我們可以:

?Sign user out on this device

?Guide to sign in again

具體怎么添加和處理摔刁,可以根據(jù)業(yè)務(wù)需求來決定。

- (void)observeAppleSignInState

{

??? if (@available(iOS 13.0, *)) {

??????? [[NSNotificationCenter defaultCenter] addObserver:self

???????????????????????????????????????????????? selector:@selector(handleSignInWithAppleStateChanged:)

???????????????????????????????????????????????????? name:ASAuthorizationAppleIDProviderCredentialRevokedNotification

???????????????? ??????????????????????????????????object:nil];

??? }

}


- (void)handleSignInWithAppleStateChanged:(NSNotification *)notification

{

??? // Sign the user out, optionally guide them to sign in again

??? NSLog(@"%@", notification.userInfo);

}

[if !supportLists]3.5.? [endif]One more thing

除此之外,蘋果還把 iCloud KeyChain password 集成到了這套 API 里拗引,我們在使用的時候矾削,只需要在創(chuàng)建 request 的時候,多創(chuàng)建一個 ASAuthorizationPasswordRequest欲间,這樣如果KeyChain 里面也有登錄信息的話括改,可以直接使用里面保存的用戶名和密碼進(jìn)行登錄嘱能。代碼如下:

- (void)signInWithAppleAPI_AVAILABLE(ios(13.0))

{

??? ASAuthorizationAppleIDProvider*appleIDProvider = [ASAuthorizationAppleIDProvider new];

??? ASAuthorizationAppleIDRequest*authAppleIDRequest = [appleIDProvider createRequest];

??? ASAuthorizationPasswordRequest*passwordRequest = [[ASAuthorizationPasswordProvider new] createRequest];


????NSMutableArray<ASAuthorizationRequest *>* array = [NSMutableArray arrayWithCapacity:2];

??? if (authAppleIDRequest) {

??????? [array addObject:authAppleIDRequest];

??? }

??? if (passwordRequest) {

??????? [array addObject:passwordRequest];

??? }

??? NSArray<ASAuthorizationRequest *>* requests = [array copy];


????ASAuthorizationController*authorizationController = [[ASAuthorizationController alloc] initWithAuthorizationRequests:requests];

??? authorizationController.delegate = self;

??? authorizationController.presentationContextProvider = self;

??? [authorizationController performRequests];

}


#pragma mark - ASAuthorizationControllerDelegate


- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(ios(13.0))

{

??? if ([authorization.credential isKindOfClass:[ASPasswordCredential class]]) {

??????? ASPasswordCredential*passwordCredential = authorization.credential;

??????? NSString*userIdentifier = passwordCredential.user;

??????? NSString*password = passwordCredential.password;


????????NSLog(@"userIdentifier: %@", userIdentifier);

??????? NSLog(@"password: %@", password);

??? }

}


4.本地化:必要且重要的一點(diǎn)

按鈕顯示的文字都是英文的惹骂,而且我們不可以修改文字对粪,總不能在國內(nèi)也展示個英文只需要添加本地化支持就可以了,此方法適用于一切系統(tǒng)文案纱扭,比如我們創(chuàng)建的 UIBarButtonSystemItemSave 乳蛾,添加簡體中文支持后鄙币,他顯示的文案就變成 保存



5.Sign In with Apple 和 Continue with Apple登錄的區(qū)別

只是文案的不同而已十嘿,中文意思分別為:通過Apple登錄、通過Apple繼續(xù)

6.蘋果第三方登錄與己方后臺服務(wù)賬號相互認(rèn)證問題

在第三方登錄出現(xiàn)之前蹦魔,大部分用戶賬戶注冊與登錄流程都是雙輸?shù)木置妫?/p>

用戶方面:為了安全性而設(shè)置的密碼往往復(fù)雜又冗余版姑,既容易忘記輸入又很麻煩迟郎,同時各種難度的驗(yàn)證碼和各種驗(yàn)證問題,不僅過濾機(jī)器人也能過濾真人聪蘸,加上手機(jī)驗(yàn)證碼等等繁瑣步驟宪肖,讓注冊登錄變得異常煩心表制。

服務(wù)商方面:加上各種驗(yàn)證步驟會明顯降低用戶體驗(yàn),可是不加又會導(dǎo)致用戶賬戶不安全和各種機(jī)器人賬號泛濫控乾,更不用說還要自己探索實(shí)現(xiàn)各種驗(yàn)證步驟么介,一不小心就會出現(xiàn)漏洞。很多時候最后這些繁瑣的步驟也沒有擋住日益智能的機(jī)器人蜕衡,反而擋住了很多正常用戶壤短。

[if !supportLists]·??????[endif]為了解決上面提到的各種問題,開放授權(quán)(OAuth)在 2010 年應(yīng)運(yùn)而生慨仿。簡單來講它是一個開放標(biāo)準(zhǔn),允許用戶在不提供密碼的情況下镰吆,授權(quán)接入了 A 網(wǎng)站第三方登錄支持的第三方應(yīng)用帘撰,訪問自己在 A 網(wǎng)站上的特定數(shù)據(jù)

[if !supportLists]·??????[endif]接著為了解決安全性問題万皿,OAuth

2.0 誕生了摧找,同時有人發(fā)現(xiàn)了這個標(biāo)準(zhǔn)很適合用來登錄驗(yàn)證用戶身份,于是基于此延伸的標(biāo)準(zhǔn)牢硅,專門解決第三方客戶端標(biāo)使用身份認(rèn)證的問題的 OIDC(OpenID Connect) 誕生了〉旁牛現(xiàn)在我們見到的大多數(shù)第三方登錄都是基于 OIDC 或者利用 OAuth 2.0 修改實(shí)現(xiàn)。

第三方登錄的原理

因?yàn)?QQ/微信/微博等平臺(以下簡稱第一方平臺)擁有完整的登錄驗(yàn)證步驟减余,用戶在上面已經(jīng)充分地證明了「我是真的我」婆赠。所以,第三方網(wǎng)站與服務(wù)只要接入了這些平臺的第三方登錄 SDK(開發(fā)組件)佳励,用戶點(diǎn)擊第三方登錄按鈕時:

網(wǎng)站或服務(wù)會通過第三方登錄 SDK 向第一方平臺發(fā)送登錄請求休里。

第一方平臺接收到登錄請求,確認(rèn)用戶設(shè)備上有沒有已經(jīng)登錄的第一方平臺賬戶赃承,如果沒有用戶需要先手動登錄第一方平臺妙黍。

如果用戶已經(jīng)在設(shè)備上登錄了第一方平臺賬戶,那么第一方平臺會返回唯一的不變的 ID(OpenID)瞧剖。

第三方網(wǎng)站與服務(wù)將這個 ID 儲存到自己的服務(wù)器上拭嫁,以后就能通過這個 ID 確認(rèn)用戶了。


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末抓于,一起剝皮案震驚了整個濱河市做粤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌捉撮,老刑警劉巖怕品,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異巾遭,居然都是意外死亡肉康,警方通過查閱死者的電腦和手機(jī)闯估,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吼和,“玉大人涨薪,你說我怎么就攤上這事§排遥” “怎么了刚夺?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長末捣。 經(jīng)常有香客問我光督,道長,這世上最難降的妖魔是什么塔粒? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任结借,我火速辦了婚禮,結(jié)果婚禮上卒茬,老公的妹妹穿的比我還像新娘船老。我一直安慰自己,他們只是感情好圃酵,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布柳畔。 她就那樣靜靜地躺著,像睡著了一般郭赐。 火紅的嫁衣襯著肌膚如雪薪韩。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天捌锭,我揣著相機(jī)與錄音俘陷,去河邊找鬼。 笑死观谦,一個胖子當(dāng)著我的面吹牛拉盾,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播豁状,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼捉偏,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了泻红?” 一聲冷哼從身側(cè)響起夭禽,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎谊路,沒想到半個月后讹躯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年蜀撑,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片剩彬。...
    茶點(diǎn)故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡酷麦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出喉恋,到底是詐尸還是另有隱情沃饶,我是刑警寧澤,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布轻黑,位于F島的核電站糊肤,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏氓鄙。R本人自食惡果不足惜馆揉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望抖拦。 院中可真熱鬧升酣,春花似錦、人聲如沸态罪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽复颈。三九已至绩聘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間耗啦,已是汗流浹背凿菩。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留帜讲,地道東北人蓄髓。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像舒帮,于是被迫代替她去往敵國和親会喝。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評論 2 354