iOS 苹果第三方登录

iOS 13-Sign In with Apple

最近了解了iOS 13新增功能之Sign In with AppleSign In with Apple是跨平台的,可以支持iOS、macOS、watchOS、tvOS、JS。本文主要内容为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审核指南更新

  • 开发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(@"////////");

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

  • 已经使用Sign In with Apple登录过app的用户
    如果设备中存在iCloud Keychain凭证或者AppleID凭证,提示用户直接使用TouchIDFaceID登录即可,代码如下
// 如果存在iCloud Keychain 凭证或者AppleID 凭证提示用户
- (void)perfomExistingAccountSetupFlows{
    NSLog(@"///已经认证过了/////");

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

  1. 获取授权码
    获取授权码需要在代码中实现两个代理回调ASAuthorizationControllerDelegate、ASAuthorizationControllerPresentationContextProviding分别用于处理授权登录成功和失败、以及提供用于展示授权页面的Window,代码如下
#pragma mark - delegate
//@optional 授权成功地回调
- (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.
        // 用户登录使用现有的密码凭证
        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;
    }
}

// 授权失败的回调
- (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 展示内容给用户
- (ASPresentationAnchor)presentationAnchorForAuthorizationController:(ASAuthorizationController *)controller{
    NSLog(@"88888888888");
    // 返回window
    return self.view.window;
}

在授权登录成功回调中,我们可以拿到以下几类数据

  • UserID:Unique, stable, team-scoped user ID,苹果用户唯一标识符,该值在同一个开发者账号下的所有App下是一样的,开发者可以用该唯一标识符与自己后台系统的账号体系绑定起来(这与国内的微信、QQ、微博等第三方登录流程基本一致)
  • Verification data:Identity token, code,验证数据,用于传给开发者后台服务器,然后开发者服务器再向苹果的身份验证服务端验证,本次授权登录请求数据的有效性和真实性,详见Sign In with Apple REST API
  • Account information:Name, verified email,苹果用户信息,包括全名、邮箱等,注意:如果玩家登录时拒绝提供真实的邮箱账号,苹果会生成虚拟的邮箱账号
  1. 验证
    关于验证的这一步,需要传递授权码给自己的服务端,自己的服务端调用苹果API去校验授权码Generate and validate tokens。如果验证成功,可以根据userIdentifier判断账号是否已存在,若存在,则返回自己账号系统的登录态,若不存在,则创建一个新的账号,并返回对应的登录状态给App

附:官方示例代码 Swift 版
附:What the Heck is Sign In with Apple?
附:苹果授权登陆后端验证
附:App Store审核指南的更新
附:Generate and validate tokens
附:SignInAppleDemo
附:我的博客地址

你可能感兴趣的:(iOS 苹果第三方登录)