iOS13 sign in with Apple客戶端接入遇到的一些問題

公司項目需要接入sign in with Apple,花了幾天時間,查看各種文檔博客,最終完成接入。
客戶端接入遇到的一些問題
1.首次登錄時調用的代碼:

if (@available(iOS 13.0, *)) {
        // 基於用戶的Apple ID授權用戶,生成用戶授權請求的一種機制
        ASAuthorizationAppleIDProvider *appleIDProvider = [[ASAuthorizationAppleIDProvider alloc] init];
        // 創建新的AppleID 授權請求
        ASAuthorizationAppleIDRequest *appleIDRequest = [appleIDProvider createRequest];
        // 在用戶授權期間請求的聯繫信息
        appleIDRequest.requestedScopes = @[ASAuthorizationScopeFullName, ASAuthorizationScopeEmail];
        // 由ASAuthorizationAppleIDProvider創建的授權請求 管理授權請求的控制器
        ASAuthorizationController *authorizationController = [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[appleIDRequest]];
        // 設置授權控制器通知授權請求的成功與失敗的代理
        authorizationController.delegate = self;
        // 設置提供 展示上下文的代理,在這個上下文中 系統可以展示授權界面給用戶
        authorizationController.presentationContextProvider = self;
        // 在控制器初始化期間啓動授權流
        [authorizationController performRequests];
    }else{
        // 處理不支持系統版本
        NSLog(@"該系統版本不可用Apple登錄");
    }

2.已經授權過,再次登錄的時候,如果你已經開啓了Touch id或者Face ID,直接使用Touch id或者Face ID登錄,沒有開啓的話,使用密碼登錄,sign in Apple沒有自動登錄接口,如果自己項目中需要自動登錄功能,不考慮服務器驗證的情況下,可以使用自己的pid和token登錄,但是這會有一定的安全性,具體代碼如下:

if (@available(iOS 13.0, *)) {
        // 基於用戶的Apple ID授權用戶,生成用戶授權請求的一種機制
        ASAuthorizationAppleIDProvider *appleIDProvider = [[ASAuthorizationAppleIDProvider alloc] init];
        // 授權請求AppleID
        ASAuthorizationAppleIDRequest *appleIDRequest = [appleIDProvider createRequest];
        // 爲了執行鑰匙串憑證分享生成請求的一種機制
        ASAuthorizationPasswordProvider *passwordProvider = [[ASAuthorizationPasswordProvider alloc] init];
        ASAuthorizationPasswordRequest *passwordRequest = [passwordProvider createRequest];
        // 由ASAuthorizationAppleIDProvider創建的授權請求 管理授權請求的控制器
        ASAuthorizationController *authorizationController = [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[appleIDRequest, passwordRequest]];
        // 設置授權控制器通知授權請求的成功與失敗的代理
        authorizationController.delegate = self;
        // 設置提供 展示上下文的代理,在這個上下文中 系統可以展示授權界面給用戶
        authorizationController.presentationContextProvider = self;
        // 在控制器初始化期間啓動授權流
        [authorizationController performRequests];
        
    }else{
        // 處理不支持系統版本
        NSLog(@"該系統版本不可用Apple登錄");
    }

3.sign in Apple登錄授權成功回調的代碼,值得注意的是familyName ,givenName ,email 只有第一次登錄的時候纔有值,再次登錄返回都是空值;ASPasswordCredential 回調我是一直測試不出來,目前不知道怎樣登錄才能收到ASPasswordCredential 的回調,具體代碼如下:

- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(ios(13.0)){
    if ([authorization.credential isKindOfClass:[ASAuthorizationAppleIDCredential class]]) {
        ASAuthorizationAppleIDCredential *appleIDCredential = authorization.credential;
        NSString *user = appleIDCredential.user;
        NSString *state = appleIDCredential.state;
        // 使用過授權的,可能獲取不到以下三個參數
        NSString *familyName = appleIDCredential.fullName.familyName;
        NSString *givenName = appleIDCredential.fullName.givenName;
        NSString *email = appleIDCredential.email;
        ASUserDetectionStatus realUserStatus = appleIDCredential.realUserStatus;
        NSLog(@"familyName=%@", familyName);
        NSLog(@"givenName=%@", givenName);
        NSLog(@"email=%@", email);
        NSLog(@"state=%@", state);
        NSLog(@"user=%@", user);
        if (user) {
            [AppleKeychain save:KEYCHAIN_IDENTIFIER(@"userIdentifier") data:user];
        }
        NSLog(@"realUserStatus=%ld", (long)realUserStatus);
        NSData *identityToken = appleIDCredential.identityToken;
        NSData *authorizationCode = appleIDCredential.authorizationCode;
        
        // 服務器驗證需要使用的參數
        NSString *identityTokenStr = [[NSString alloc] initWithData:identityToken encoding:NSUTF8StringEncoding];
        NSString *authorizationCodeStr = [[NSString alloc] initWithData:authorizationCode encoding:NSUTF8StringEncoding];
        NSLog(@"%@\n\n%@", identityTokenStr, authorizationCodeStr);
        if (identityTokenStr&&authorizationCodeStr) {
            [self doLoginVerify:identityTokenStr AndCode:authorizationCodeStr];
        }
        
    }else if ([authorization.credential isKindOfClass:[ASPasswordCredential class]]){
        // 這個獲取的是iCloud記錄的賬號密碼,需要輸入框支持iOS 12 記錄賬號密碼的新特性
        //這個回調我是沒有測試出來過,不知道怎麼搞
        // Sign in using an existing iCloud Keychain credential.
        // 用戶登錄使用現有的密碼憑證
        NSLog(@"Sign in using an existing iCloud Keychain credential");
        ASPasswordCredential *passwordCredential = authorization.credential;
        // 密碼憑證對象的用戶標識 用戶的唯一標識
        NSString *user = passwordCredential.user;
        // 密碼憑證對象的密碼
        NSString *password = passwordCredential.password;
        NSLog(@"user=%@", user);
        NSLog(@"password=%@", password);
    }else{
        NSLog(@"授權信息均不符");
        
    }
}

4.蘋果登錄觀察授權狀態監聽,如果你切換一個新的Apple id或者停止使用Apple id,那麼回調的結果是不一樣的,根據自己項目做處理,正常情況,你只要使用sign in Apple登錄過一次,那麼下次再登錄的時候,回調都是授權狀態良好,具體代碼如下:

 if (@available(iOS 13.0, *)) {
        // A mechanism for generating requests to authenticate users based on their Apple ID.
        // 基於用戶的Apple ID 生成授權用戶請求的機制
        ASAuthorizationAppleIDProvider *appleIDProvider = [ASAuthorizationAppleIDProvider new];
        // 注意 存儲用戶標識信息需要使用鑰匙串來存儲 這裏筆者簡單期間 使用NSUserDefaults 做的簡單示例
        NSString *userIdentifier = [AppleKeychain load:KEYCHAIN_IDENTIFIER(@"userIdentifier")];
        NMGLog(@"observeAuthticationState----:%@",userIdentifier);
        if (userIdentifier) {
            NSString* __block errorMsg = nil;
            //Returns the credential state for the given user in a completion handler.
            // 在回調中返回用戶的授權狀態
            [appleIDProvider getCredentialStateForUserID:userIdentifier completion:^(ASAuthorizationAppleIDProviderCredentialState credentialState, NSError * _Nullable error) {
                switch (credentialState) {
                        // 蘋果證書的授權狀態
                    case ASAuthorizationAppleIDProviderCredentialRevoked:
                        // 蘋果授權憑證失效
                        errorMsg = @"蘋果授權憑證失效";
                        [self logout];
                        break;
                    case ASAuthorizationAppleIDProviderCredentialAuthorized:
                        // 蘋果授權憑證狀態良好
                        errorMsg = @"蘋果授權憑證狀態良好";
                        break;
                    case ASAuthorizationAppleIDProviderCredentialNotFound:
                        // 未發現蘋果授權憑證
                        errorMsg = @"未發現蘋果授權憑證";
                        [self logout];
                        break;
                        // 可以引導用戶重新登錄
                    case ASAuthorizationAppleIDProviderCredentialTransferred:
                        errorMsg = @"蘋果授權信息變動";
                        break;
                }
                dispatch_async(dispatch_get_main_queue(), ^{
                    NSLog(@"SignInWithApple授權狀態變化情況");
                    NSLog(@"%@", errorMsg);
                });
            }];
            
        }
    }

5.能不能自定義sign in Apple按鈕這個問題,我們也發郵件去諮詢了蘋果公司,回覆的是:you best to use the familiar buttons that Apple provides for Sign in with Apple,但是最終我們沒有使用系統自帶的ASAuthorizationAppleIDButton ,而是按照設計規範自己設計按鈕。目前無法確定是否可以提審成功。
一些參考文檔:
https://developer.apple.com/design/human-interface-guidelines/sign-in-with-apple/overview/
https://developer.apple.com/documentation/signinwithapplerestapi/authenticating_users_with_sign_in_with_apple#see-also

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章