iOS 蘋果第三方登錄

iOS 13-Sign In with Apple

最近了解了iOS 13新增功能之Sign In with Apple千绪,Sign In with Apple是跨平臺的杂彭,可以支持iOS锥腻、macOS初坠、watchOS涵防、tvOS、JS栏账。本文主要內(nèi)容為Sign In with AppleiOS上的基礎使用。詳情參考WWDC 2019

  • 審核備注

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.
也就是說栈源,當 Sign In with Apple 服務正式上線以后挡爵,所有已接入其它第三方登錄的 App,Sign In with Apple 將被要求作為一種登錄選擇甚垦,否則有可能就不給過茶鹃。詳情參考App Store審核指南更新

  • 開發(fā)Sign In with Apple的注意事項
    需要在蘋果后臺打開該選項,并且重新生成Profiles配置文件艰亮,并安裝到Xcode闭翩,如下圖

    image
  • iOS使用Sign In with AppleXcode的準備工作
    Xcode11 Signing & Capabilities中添加Sign In With Apple,如下圖

    image
  • iOS Sign In with Apple流程

  1. 添加 Sign In with Apple 登錄按鈕迄埃,設置 ASAuthorizationAppleIDButton 相關布局疗韵,并添加按鈕點擊響應事件
  2. 獲取授權碼
  3. 驗證
  1. 添加Sign In with Apple登錄按鈕,設置ASAuthorizationAppleIDButton相關布局侄非,并添加按鈕點擊響應事件蕉汪。當然蘋果也允許自定義蘋果登錄按鈕的樣式,樣式要求詳見這個文檔:Human Interface Guidelines
- (void)configUI{
    // 用于展示Sign In With Apple 登錄過程的信息
    _appleIDInfoLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 40.0, CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame) * 0.4)];
    _appleIDInfoLabel.font = [UIFont systemFontOfSize:22.0];
    _appleIDInfoLabel.numberOfLines = 0;
    _appleIDInfoLabel.lineBreakMode = NSLineBreakByWordWrapping;
    _appleIDInfoLabel.text = @"顯示Sign In With Apple 登錄信息\n";
    [self.view addSubview:_appleIDInfoLabel];

    if (@available(iOS 13.0, *)) {
        // Sign In With Apple Button
        ASAuthorizationAppleIDButton *appleIDBtn = [ASAuthorizationAppleIDButton buttonWithType:ASAuthorizationAppleIDButtonTypeDefault style:ASAuthorizationAppleIDButtonStyleWhite];
        appleIDBtn.frame = CGRectMake(30, self.view.bounds.size.height - 180, self.view.bounds.size.width - 60, 100);
        //    appleBtn.cornerRadius = 22.f;
        [appleIDBtn addTarget:self action:@selector(handleAuthorizationAppleIDButtonPress) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:appleIDBtn];
    }
}

// 處理授權
- (void)handleAuthorizationAppleIDButtonPress{
    NSLog(@"http:////////");

    if (@available(iOS 13.0, *)) {
        // 基于用戶的Apple ID授權用戶逞怨,生成用戶授權請求的一種機制
        ASAuthorizationAppleIDProvider *appleIDProvider = [[ASAuthorizationAppleIDProvider alloc] init];
        // 創(chuàng)建新的AppleID 授權請求
        ASAuthorizationAppleIDRequest *appleIDRequest = [appleIDProvider createRequest];
        // 在用戶授權期間請求的聯(lián)系信息
        appleIDRequest.requestedScopes = @[ASAuthorizationScopeFullName, ASAuthorizationScopeEmail];
        // 由ASAuthorizationAppleIDProvider創(chuàng)建的授權請求 管理授權請求的控制器
        ASAuthorizationController *authorizationController = [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[appleIDRequest]];
        // 設置授權控制器通知授權請求的成功與失敗的代理
        authorizationController.delegate = self;
        // 設置提供 展示上下文的代理者疤,在這個上下文中 系統(tǒng)可以展示授權界面給用戶
        authorizationController.presentationContextProvider = self;
        // 在控制器初始化期間啟動授權流
        [authorizationController performRequests];
    }
}

  • 已經(jīng)使用Sign In with Apple登錄過app的用戶
    如果設備中存在iCloud Keychain憑證或者AppleID憑證,提示用戶直接使用TouchIDFaceID登錄即可叠赦,代碼如下
// 如果存在iCloud Keychain 憑證或者AppleID 憑證提示用戶
- (void)perfomExistingAccountSetupFlows{
    NSLog(@"http:///已經(jīng)認證過了/////");

    if (@available(iOS 13.0, *)) {
        // 基于用戶的Apple ID授權用戶驹马,生成用戶授權請求的一種機制
        ASAuthorizationAppleIDProvider *appleIDProvider = [[ASAuthorizationAppleIDProvider alloc] init];
        // 授權請求AppleID
        ASAuthorizationAppleIDRequest *appleIDRequest = [appleIDProvider createRequest];
        // 為了執(zhí)行鑰匙串憑證分享生成請求的一種機制
        ASAuthorizationPasswordProvider *passwordProvider = [[ASAuthorizationPasswordProvider alloc] init];
        ASAuthorizationPasswordRequest *passwordRequest = [passwordProvider createRequest];
        // 由ASAuthorizationAppleIDProvider創(chuàng)建的授權請求 管理授權請求的控制器
        ASAuthorizationController *authorizationController = [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[appleIDRequest, passwordRequest]];
        // 設置授權控制器通知授權請求的成功與失敗的代理
        authorizationController.delegate = self;
        // 設置提供 展示上下文的代理,在這個上下文中 系統(tǒng)可以展示授權界面給用戶
        authorizationController.presentationContextProvider = self;
        // 在控制器初始化期間啟動授權流
        [authorizationController performRequests];
    }
}

  1. 獲取授權碼
    獲取授權碼需要在代碼中實現(xiàn)兩個代理回調(diào)ASAuthorizationControllerDelegate除秀、ASAuthorizationControllerPresentationContextProviding分別用于處理授權登錄成功和失敗糯累、以及提供用于展示授權頁面的Window,代碼如下
#pragma mark - delegate
//@optional 授權成功地回調(diào)
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization{
    NSLog(@"授權完成:::%@", authorization.credential);
    NSLog(@"%s", __FUNCTION__);
    NSLog(@"%@", controller);
    NSLog(@"%@", authorization);

    // 測試配置UI顯示
    NSMutableString *mStr = [NSMutableString string];

    if ([authorization.credential isKindOfClass:[ASAuthorizationAppleIDCredential class]]) {
        // 用戶登錄使用ASAuthorizationAppleIDCredential
        ASAuthorizationAppleIDCredential *appleIDCredential = authorization.credential;
        NSString *user = appleIDCredential.user;
        NSString *familyName = appleIDCredential.fullName.familyName;
        NSString *givenName = appleIDCredential.fullName.givenName;
        NSString *email = appleIDCredential.email;
//        NSData *identityToken = appleIDCredential.identityToken;
//        NSData *authorizationCode = appleIDCredential.authorizationCode;
        // Create an account in your system.
        // For the purpose of this demo app, store the userIdentifier in the keychain.
        //  需要使用鑰匙串的方式保存用戶的唯一信息
        [YostarKeychain save:KEYCHAIN_IDENTIFIER(@"userIdentifier") data:user];
        [mStr appendString:user];
        [mStr appendString:@"\n"];
        [mStr appendString:familyName];
        [mStr appendString:@"\n"];
        [mStr appendString:givenName];
        [mStr appendString:@"\n"];
        [mStr appendString:email];
        NSLog(@"mStr:::%@", mStr);
        [mStr appendString:@"\n"];
        _appleIDInfoLabel.text = mStr;
    }else if ([authorization.credential isKindOfClass:[ASPasswordCredential class]]){
        // Sign in using an existing iCloud Keychain credential.
        // 用戶登錄使用現(xiàn)有的密碼憑證
        ASPasswordCredential *passwordCredential = authorization.credential;
        // 密碼憑證對象的用戶標識 用戶的唯一標識
        NSString *user = passwordCredential.user;
        // 密碼憑證對象的密碼
        NSString *password = passwordCredential.password;

        [mStr appendString:user];
        [mStr appendString:@"\n"];
        [mStr appendString:password];
        [mStr appendString:@"\n"];
        NSLog(@"mStr:::%@", mStr);
        _appleIDInfoLabel.text = mStr;
    }else{
        NSLog(@"授權信息均不符");
        mStr = [@"授權信息均不符" copy];
        _appleIDInfoLabel.text = mStr;
    }
}

// 授權失敗的回調(diào)
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithError:(NSError *)error{
    // Handle error.
    NSLog(@"Handle error:%@", error);
    NSString *errorMsg = nil;
    switch (error.code) {
        case ASAuthorizationErrorCanceled:
            errorMsg = @"用戶取消了授權請求";
            break;
        case ASAuthorizationErrorFailed:
            errorMsg = @"授權請求失敗";
            break;
        case ASAuthorizationErrorInvalidResponse:
            errorMsg = @"授權請求響應無效";
            break;
        case ASAuthorizationErrorNotHandled:
            errorMsg = @"未能處理授權請求";
            break;
        case ASAuthorizationErrorUnknown:
            errorMsg = @"授權請求失敗未知原因";
            break;

        default:
            break;
    }

    NSMutableString *mStr = [_appleIDInfoLabel.text mutableCopy];
    [mStr appendString:@"\n"];
    [mStr appendString:errorMsg];
    [mStr appendString:@"\n"];
    _appleIDInfoLabel.text = mStr;
}

// 告訴代理應該在哪個window 展示內(nèi)容給用戶
- (ASPresentationAnchor)presentationAnchorForAuthorizationController:(ASAuthorizationController *)controller{
    NSLog(@"88888888888");
    // 返回window
    return self.view.window;
}

在授權登錄成功回調(diào)中册踩,我們可以拿到以下幾類數(shù)據(jù)

  • UserID:Unique, stable, team-scoped user ID泳姐,蘋果用戶唯一標識符,該值在同一個開發(fā)者賬號下的所有App下是一樣的棍好,開發(fā)者可以用該唯一標識符與自己后臺系統(tǒng)的賬號體系綁定起來(這與國內(nèi)的微信仗岸、QQ、微博等第三方登錄流程基本一致)
  • Verification data:Identity token, code借笙,驗證數(shù)據(jù)扒怖,用于傳給開發(fā)者后臺服務器,然后開發(fā)者服務器再向蘋果的身份驗證服務端驗證业稼,本次授權登錄請求數(shù)據(jù)的有效性和真實性盗痒,詳見Sign In with Apple REST API
  • Account information:Name, verified email,蘋果用戶信息,包括全名俯邓、郵箱等骡楼,注意:如果玩家登錄時拒絕提供真實的郵箱賬號,蘋果會生成虛擬的郵箱賬號
  1. 驗證
    關于驗證的這一步稽鞭,需要傳遞授權碼給自己的服務端鸟整,自己的服務端調(diào)用蘋果API去校驗授權碼Generate and validate tokens。如果驗證成功朦蕴,可以根據(jù)userIdentifier判斷賬號是否已存在篮条,若存在,則返回自己賬號系統(tǒng)的登錄態(tài)吩抓,若不存在涉茧,則創(chuàng)建一個新的賬號,并返回對應的登錄狀態(tài)給App

附:官方示例代碼 Swift 版
附:What the Heck is Sign In with Apple?
附:蘋果授權登陸后端驗證
附:App Store審核指南的更新
附:Generate and validate tokens
附:SignInAppleDemo
附:我的博客地址

</article>

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末疹娶,一起剝皮案震驚了整個濱河市伴栓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌雨饺,老刑警劉巖钳垮,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異沛膳,居然都是意外死亡扔枫,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進店門锹安,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人倚舀,你說我怎么就攤上這事叹哭。” “怎么了痕貌?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵风罩,是天一觀的道長。 經(jīng)常有香客問我舵稠,道長超升,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任哺徊,我火速辦了婚禮室琢,結果婚禮上,老公的妹妹穿的比我還像新娘落追。我一直安慰自己盈滴,他們只是感情好,可當我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布轿钠。 她就那樣靜靜地躺著巢钓,像睡著了一般病苗。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上症汹,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天硫朦,我揣著相機與錄音,去河邊找鬼背镇。 笑死阵幸,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的芽世。 我是一名探鬼主播挚赊,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼济瓢!你這毒婦竟也來了荠割?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤旺矾,失蹤者是張志新(化名)和其女友劉穎蔑鹦,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體箕宙,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡嚎朽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了柬帕。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哟忍。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖陷寝,靈堂內(nèi)的尸體忽然破棺而出锅很,到底是詐尸還是另有隱情,我是刑警寧澤凤跑,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布爆安,位于F島的核電站,受9級特大地震影響仔引,放射性物質(zhì)發(fā)生泄漏扔仓。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一咖耘、第九天 我趴在偏房一處隱蔽的房頂上張望翘簇。 院中可真熱鬧,春花似錦鲤看、人聲如沸缘揪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽找筝。三九已至蹈垢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間袖裕,已是汗流浹背曹抬。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留急鳄,地道東北人谤民。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像疾宏,于是被迫代替她去往敵國和親张足。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內(nèi)容