iOS 13蘋果登錄


https://blog.csdn.net/MarinaTsang/article/details/104883928

https://blog.csdn.net/yuao_708905482/article/details/104042158

https://www.ho35.com/artinfo-1339.html

 

Sign in with Apple

前言
准備工作
開發工作(object-c編寫)
基本流程
添加依賴庫
創建Apple登錄Button
向Apple發起請求
接收Apple的回調
注意:
用戶注銷 AppleId 或 停止使用 Apple ID 的狀態處理
服務端驗證
參數的獲取方法:
Q&A
前言

根據Apple發布的新政策,如果你的App有第三方登錄,例如微信、QQ、Facebook、twitter等第三方登錄一定需要增加AppleID的登錄方式。具體可以參考Apple的官方文檔:

https://developer.apple.com/cn/app-store/review/guidelines/#sign-in-with-apple

2020.04月上架或更新的Apple適用:https://developer.apple.com/cn/news/

Apple登錄免用戶密碼輸入,並且可以修改顯示的名稱及隱藏電子郵箱,安全性很高。

准備工作

Apple原生的SDK只適用於iOS 13.0+ 系統,測試時需要一台13+系統測試機。

升級Xcode 到 11+版本。

開發者后台對應的indentify下勾選 sign in with apple登錄選項,重新下載profiler文件。步驟如下:

登錄您的Apple開發者賬號-

選擇左邊 Identifier 欄目,在右側選擇要開通 **蘋果授權登錄(Sign in with Apple)**的 Identifiers 點擊打開。

下拉找到 Sign In with Apple 打鈎。

 

點擊 右上角 save 保存會出現 Modify App Capabilities 彈窗 點擊 Confirm
注:開啟后 profile 將失效需要重新編輯 profile 文件。

在xcode項目中開啟sign in with apple,步驟如下:

在左側PROJECT中選擇對應的項目target
選擇signing & capabilities,點擊Capability,搜索sign in with apple,雙擊即可。
開發工作(object-c編寫)

基本流程

創建 Apple登錄Button
向Apple發起請求
處理Apple登錄后的結果
將Apple登錄后的用戶信息傳給服務器端驗證(可選)
處理用戶更換AppleID或停用AppleID問題。
初次登錄時可以讓用戶編輯顯示的用戶名及是否隱藏郵箱,第二次登錄之后用戶進行認證即可。

 

蘋果開發官方文檔:https://developer.apple.com/documentation/authenticationservices

添加依賴庫

在選擇project-build phase -link binary with libraries-搜索 AuthenticationServices.framework 添加。

創建Apple登錄Button

Apple提供了官方sign in with apple button,如果需要自定義按鈕,自定義按鈕的規則如下:https://developer.apple.com/documentation/signinwithapplejs/incorporating_sign_in_with_apple_into_other_platforms

if (@available(iOS 13.0,*)) {
ASAuthorizationAppleIDButtonType type = ASAuthorizationAppleIDButtonTypeSignIn;
ASAuthorizationAppleIDButton* authorizationButton = [ASAuthorizationAppleIDButton buttonWithType:type style:ASAuthorizationAppleIDButtonStyleWhite];
// add to your viewcontainer
....
[authorizationButton addTarget:self action:@selector(showAppleLogin) forControlEvents:UIControlEventTouchUpInside];

[_firstLoginView addSubview:authorizationButton];
}

-(void)showAppleLogin{
// add your code to apple login
.....
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Button 的type有登錄類型ASAuthorizationAppleIDButtonTypeSignIn和注冊類型ASAuthorizationAppleIDButtonTypeSignUp(只能在13.2+有效,13.0-13.2需要自定義)。

Button的style的有幾種類型,但都是黑白配。

 

向Apple發起請求

蘋果還把 iCloud KeyChain password 集成到了這套 API 里,我們在使用的時候,只需要在創建 request 的時候,多創建一個 ASAuthorizationPasswordRequest,這樣如果 KeyChain 里面也有登錄信息的話,可以直接使用里面保存的用戶名和密碼進行登錄。

#import <AuthenticationServices/AuthenticationServices.h>

-(void)signInWithAppleNative API_AVAILABLE(ios(13.0)){
ASAuthorizationAppleIDProvider *provider = [[ASAuthorizationAppleIDProvider alloc] init];
ASAuthorizationAppleIDRequest *authAppleIDRequest = [provider createRequest];
// 在用戶授權期間請求的聯系信息
authAppleIDRequest.requestedScopes = @[ASAuthorizationScopeFullName, ASAuthorizationScopeEmail];

// 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];

// 由ASAuthorizationAppleIDProvider創建的授權請求 管理授權請求的控制器
ASAuthorizationController *authorizationController = [[ASAuthorizationController alloc] initWithAuthorizationRequests:requests];
authorizationController.delegate = self;
// 設置提供 展示上下文的代理,在這個上下文中 系統可以展示授權界面給用戶
authorizationController.presentationContextProvider = self;

// 在控制器初始化期間啟動授權流
[authorizationController performRequests];
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
注:

1、sign in with apple 工具類設成全局變量,或使用單例類,如果使用局部變量,和IAP工具類一樣蘋果的回調不會執行。

**2、當啟用 **ASAuthorizationPasswordRequest 且 停止使用 Apple ID(真機-設置-賬戶-密碼與安全性-使用您 Apple ID 的 App-App列表-停止使用 Apple ID),如果 KeyChain 里面沒有登錄信息且重新使用 蘋果授權登錄(Sign in with Apple) 會報未知錯誤.

SignInWithApple[2759:550203] [core] Authorization failed: Error Domain=AKAuthenticationError Code=-7001 "(null)" UserInfo={AKClientBundleID=com.wangquanwei.SignInWithApple}
1
接收Apple的回調

// 成功的回調
-(void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(ios(13.0)){

// the credential is an Apple ID
if([authorization.credential isKindOfClass:[ASAuthorizationAppleIDCredential class]]){
// 獲取信息並將信息保存在 鑰匙串中
ASAuthorizationAppleIDCredential *authorizeCredential = authorization.credential;
NSString * nickname = authorizeCredential.fullName.givenName;
NSString * userID = authorizeCredential.user; // 同一個開發者賬號下的app 返回的值一樣的
NSString * email = authorizeCredential.email;
NSData * authorizationCode = authorizeCredential.authorizationCode;
NSData * identityToken =authorizeCredential.identityToken;

// 將ID保存到鑰匙串--示例
if (userID) {
[Utility setKeychainValue:[userID dataUsingEncoding:NSUTF8StringEncoding] key:@"appleUserID"];
}
// NSLog(@"state: %@", state);
NSLog(@"userID: %@", userID);
NSLog(@"fullName: %@", nickname);
NSLog(@"email: %@", email);
NSLog(@"authorizationCode: %@", authorizationCode);
NSLog(@"identityToken: %@", [[NSString alloc] initWithData:identityToken encoding:NSUTF8StringEncoding] );
// NSLog(@"realUserStatus: %@", @(realUserStatus));
// 示例-將信息回調到服務器端進行驗證
[self setAppleUserCallback:YES userId:userID authorizeCode:authorizationCode identityToken:identityToken name:nickname];


// If the credential is a password credential, the system displays an alert allowing the user to authenticate with the existing account.
}else if ([authorization.credential isKindOfClass:[ASPasswordCredential class]]) {
ASPasswordCredential *passwordCredential = authorization.credential;
NSString *userIdentifier = passwordCredential.user;
NSString *password = passwordCredential.password;

// 可以直接登錄
// NSLog(@"userIdentifier: %@", userIdentifier);
// NSLog(@"password: %@", password);
[self setAppleUserCallback:YES userId:userIdentifier authorizeCode:nil identityToken:nil name:nil];
}
}

// 失敗的回調
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithError:(NSError *)error
API_AVAILABLE(ios(13.0)){

NSString * errorMsg = nil;
AppleLoginCallbackVO *kvo = [[AppleLoginCallbackVO alloc] init];
kvo.isSucceed = NO;
switch (error.code) {
case ASAuthorizationErrorCanceled:
errorMsg = @"Authorization is cancled.";
break;
case ASAuthorizationErrorFailed:
errorMsg = @"Authorize failed.";
break;
case ASAuthorizationErrorInvalidResponse:
errorMsg = @"Authoraized response invalid.";
break;
case ASAuthorizationErrorNotHandled:
errorMsg = @"Authorization can not handle.";
break;
case ASAuthorizationErrorUnknown:
default:
errorMsg = @"Unknown reason failed for authorization.";
break;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
注意:

獲取的用戶信息中:email、NSPersonNameComponents對象所有屬性是只有第一次請求的時候才會返回,之后就算 停止使用 Apple ID 再重新授權都不會返回用戶信息。
authorizeCredential.user 是用戶的唯一ID,同一個開發者賬號下這個ID一致。
authorizeCredential.authorizationCode驗證碼,每次返回的不一樣,看服務端使用那種驗證方式而定是否使用。
authorizeCredential.identityToken用戶的驗證token,有一定的有效期,到期后會刷新。
Apple建議將用戶ID保存在鑰匙串中以便在App啟動的時候進行檢查AppleID的登錄狀態。
用戶注銷 AppleId 或 停止使用 Apple ID 的狀態處理

在application:didFinishLaunchingWithOptions進行APPID的登錄狀態檢查。

-(void)checkAuthoriza API_AVAILABLE(ios(13.0)){
// 從鑰匙串中取出用戶ID
NSData* appleUserId = [tility valueKeyChain:@"appleUserID"];
if (appleUserId) {
NSString *appleIdentifyId = [[NSString alloc] initWithData:appleUserId encoding:NSUTF8StringEncoding];
ASAuthorizationAppleIDProvider *provider = [ASAuthorizationAppleIDProvider new];

[provider getCredentialStateForUserID:appleIdentifyId completion:^(ASAuthorizationAppleIDProviderCredentialState credentialState, NSError * _Nullable error) {
switch (credentialState) {
case ASAuthorizationAppleIDProviderCredentialAuthorized:
//
NSLog(@"has authorized");
break;
case ASAuthorizationAppleIDProviderCredentialRevoked:
NSLog(@"revoked,please sign out apple login");
// 刪除鑰匙串保存的信息
[Utility removeObjectKeyChainForKey:@"appleUserID"];
// 登出Apple登錄,等待下次重新登錄
break;
case ASAuthorizationAppleIDProviderCredentialNotFound:
NSLog(@"not found....");
[Utility removeObjectKeyChainForKey:@"appleUserID"];
default:
break;
}
}];
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2、檢查用戶的APPID的登錄狀態還可以使用觀察者的方式

// 注冊通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleSignInWithAppleStateChanged:) name:ASAuthorizationAppleIDProviderCredentialRevokedNotification object:nil];
#pragma mark- apple授權狀態 更改通知
- (void)handleSignInWithAppleStateChanged:(NSNotification *)notification
{
NSLog(@"%@", notification.userInfo);
}
1
2
3
4
5
6
7
服務端驗證

服務端驗證分兩種驗證方式:一種是驗證碼驗證、一種是JWT驗證。具體詳見Apple 官方文檔:https://developer.apple.com/documentation/signinwithapplerestapi

手機端需要提交 user 、authorizationCode 、 identityToken 字段信息(code和token字段蘋果返回的是 base64 Data 形式,手機端可以先轉換 base64 字符串之后在給服務器)到服務器。然后服務器通過 https://appleid.apple.com/auth/token 該接口,並拼接對應參數去驗證,接口相關信息蘋果有提供。

參數介紹:

Client_id:App 的BundleID
client_secret:后台生成的JWT key,生成方法見后續。
Code:客戶端傳過的authorizationCode
grant_type:常量authorizationCode
參數的獲取方法:

登錄Apple開發者賬號-menbership 獲取teamid ;

創建private_key:進入證書欄certificates、IDs&Profiles,選擇keys標簽(如果沒有keys標簽,可能是您登錄的Apple開發者賬號不是超管賬號,沒有權限。)-現在添加–給key命名並選擇對應的bundleid。

注:該private_key只能下載一次。

根據Apple返回的結果中sub字段即是用戶的ID,可以和手機端的user字段對比驗證。

Q&A

找不到AuthenticationServices

AuthenticationServices 是只有在iOS13+系統才有效,在使用對應API的時候需要限定是 13.0+

無法引入App.kit [
AppKit is not available when building for iOS. Consider using #if TARGET_OS_MACCATALYST to conditionally import this framework when building for Mac Catalyst, first importing TargetConditionals.h if necessary.

按照提示在引入App.kit 增加判斷:

#if TARGET_OS_MACCATALYST
#import <AppKit/AppKit.h>
#endif
1
2
3
Authorization failed: Error Domain=AKAuthenticationError Code=-7001 “(null)”

停止使用 ASAuthorizationPasswordRequest。
————————————————
版權聲明:本文為CSDN博主「MarinaTsang」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/MarinaTsang/article/details/104883928


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM