Apple ID 登录流程详解

Apple登录流程详解1:背景

2019年苹果推出 苹果登录(Sign in with Apple)方式,要求2020年4月之后运行在iOS13及以上系统的APP如果使用第三方或社交登录服务(如 Facebook、谷歌、 Twitter、Linkedln或亚马逊等),必须向用户提供“以苹果账号登录”服务的选项。其中苹果的审核细则4.8也明确的规定了这一点。

不过需要注意的一点是腾讯系列的产品如果只是使用微信、QQ登录并不算第三方登录,所以可以不用添加AppleID登录方式。

2:前置配置2.1 Xcode工程配置

选中工程trager,在capabilities中添加AppleID登录的能力

图片[1]-Apple ID 登录流程详解-JieYingAI捷鹰AI

2.2 开发者账号配置

基于授权码的后端验证方式需要此步骤,如果使用JWT验证方式则不依赖此步骤,不过建议按顺序看完多做了解。

该步骤的最终目的是获取用于校验客户端身份的所需内容,其中包括以下三个内容

注意:该步骤需要登录Apple开发者账号并对其进行功能的配置、开启、以及描述文件更新等操作,可能需要证书管理团队或者有相关权限的人员来处理,并由他们将对应信息输出

步骤一:能力开启

进入开发者账号,选择需要支持AppleID登录能力的应用并进入打开其AppleID登录的功能

图片[2]-Apple ID 登录流程详解-JieYingAI捷鹰AI

图片[3]-Apple ID 登录流程详解-JieYingAI捷鹰AI

步骤二:更新profile

对app的任何更改都会导致现有的profile文件失效,所以需要重新生成profile描述文件。

图片[4]-Apple ID 登录流程详解-JieYingAI捷鹰AI

按照如下路径操作,点进已经invalid的描述文件并重新生成

图片[5]-Apple ID 登录流程详解-JieYingAI捷鹰AI

步骤三:生成密钥文件

进入如下界面点击加号进行生成

图片[6]-Apple ID 登录流程详解-JieYingAI捷鹰AI

填完并勾选Sigin with apple后点击右侧的Configure进行配置,在配置页面选择需要开启苹果登录的app并保存,然后回到上一页并开始注册

图片[7]-Apple ID 登录流程详解-JieYingAI捷鹰AI

图片[8]-Apple ID 登录流程详解-JieYingAI捷鹰AI

图片[9]-Apple ID 登录流程详解-JieYingAI捷鹰AI

最终注册成功后会有KeyID、TeamID和可供下载的密钥文件

图片[10]-Apple ID 登录流程详解-JieYingAI捷鹰AI

密钥文件格式为.p8实际是文本文件

图片[11]-Apple ID 登录流程详解-JieYingAI捷鹰AI

注意:密钥文件只能被下载一次,下载后保存在安全的地方,丢了的话只能重新申请了

3:登录流程

登录流程分两大块,一个是客户端部分,一个是后端部分,其中后端部分有两种校验方式基于授权码的后端验证、基于JWT的算法验证,稍后会一一讲解。总体流程如下图:

图片[12]-Apple ID 登录流程详解-JieYingAI捷鹰AI

3.1 客户端侧步骤一:授权

对于客户端来说AppleID登录与传统的三方登录流程一样,分为调用接口与回调信息获取两步,唯一不同点是苹果登录的API是在iOS SDK内部封装,只用导入对应头文件即可#import

关于登录入口,苹果对AppleID登录的UI有严格的限制,因此专门提供了提供了一套继承于UIControl等控件来供开发者使用ASAuthorizationAppleIDButton

ASAuthorizationAppleIDButton * appleIDBtn = [ASAuthorizationAppleIDButton buttonWithType:ASAuthorizationAppleIDButtonTypeDefault style:ASAuthorizationAppleIDButtonStyleWhite];
appleIDBtn.frame = CGRectMake(0, 0, 100, 60);
[appleIDBtn addTarget:self action:@selector(didAppleIDBtnClicked) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:appleIDBtn];

其中按钮的文案类型和UI风格可以通过枚举进行配置

//  文案类型
typedef NS_ENUM(NSInteger, ASAuthorizationAppleIDButtonType) {
    ASAuthorizationAppleIDButtonTypeSignIn,
    ASAuthorizationAppleIDButtonTypeContinue,
    ASAuthorizationAppleIDButtonTypeSignUp API_AVAILABLE(ios(13.2), macos(10.15.1), tvos(13.1)) API_UNAVAILABLE(watchos),
    ASAuthorizationAppleIDButtonTypeDefault = ASAuthorizationAppleIDButtonTypeSignIn,
} NS_SWIFT_NAME(ASAuthorizationAppleIDButton.ButtonType) API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0)) API_UNAVAILABLE(watchos);
//  UI风格
typedef NS_ENUM(NSInteger, ASAuthorizationAppleIDButtonStyle) {
    ASAuthorizationAppleIDButtonStyleWhite,
    ASAuthorizationAppleIDButtonStyleWhiteOutline,
    ASAuthorizationAppleIDButtonStyleBlack,
} NS_SWIFT_NAME(ASAuthorizationAppleIDButton.Style) API_AVAILABLE(ios(13.0), macos(10.15), tvos(13.0)) API_UNAVAILABLE(watchos);

但是并不推荐这种方式使用,原因如下:

所以建议自己写UI,直接在点击事件中调用AppleID的相关API进行授权登陆操作,具体代码为,其中ASAuthorizationAppleIDRequest为是否使用Keychain信息,如果如果 KeyChain 里面也有登录信息的话,可以直接使用里面保存的用户名和密码进行登录。可以根据实际业务需求来

KINFO(@"[AppleLoginWrapper]开始苹果登录鉴权");
if (@available(iOS 13.0, *)) {
    ASAuthorizationAppleIDProvider *provider = [ASAuthorizationAppleIDProvider new];
    ASAuthorizationAppleIDRequest *request = [provider createRequest];
    request.requestedScopes = @[ ASAuthorizationScopeFullName, ASAuthorizationScopeEmail ]; //请求的用户信息
    ASAuthorizationPasswordRequest * keychainRequest = [[[ASAuthorizationPasswordProvider alloc] init] createRequest];
    ASAuthorizationController *vc = [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[ request ,keychainRequest]];
    vc.delegate = self;
    vc.presentationContextProvider = self;
    [vc performRequests];
} else {
    // Fallback on earlier versions
    KINFO(@"[AppleLoginWrapper]iOS系统低于13");
}

步骤二:信息回调

依赖的两个delegate

#pragma mark- 代理 ASAuthorizationControllerDelegate
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization {
    //  成功
    //  其中`authorization.credential`包含了Token,用户ID等授权所需信息,可上报到后台
}
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithError:(NSError *)error {
    //  失败
}
#pragma mark- 代理ASAuthorizationControllerPresentationContextProviding
- (ASPresentationAnchor)presentationAnchorForAuthorizationController:(ASAuthorizationController *)controller {
    //  展示在哪个Window上
    return self.view.window;
}

步骤三:用户ID状态校验

防止用户注销 AppleId 或 停止使用 Apple ID 的状态处理

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    if (@available(iOS 13.0, *)) {
        // 注意 存储用户标识信息需要使用钥匙串来存储 这里使用NSUserDefaults 做的简单示例
        NSString * userIdentifier = [[NSUserDefaults standardUserDefaults] valueForKey:@"appleID"];
        if (userIdentifier) {
            ASAuthorizationAppleIDProvider * appleIDProvider = [[ASAuthorizationAppleIDProvider alloc] init];
            [appleIDProvider getCredentialStateForUserID:userIdentifier
                                              completion:^(ASAuthorizationAppleIDProviderCredentialState credentialState, NSError * _Nullable error) {
                switch (credentialState) {
                    case ASAuthorizationAppleIDProviderCredentialAuthorized:
                        // 授权状态有效
                        break;
                    case ASAuthorizationAppleIDProviderCredentialRevoked:
                        // 苹果账号登录的凭据已被移除,需解除绑定并重新引导用户使用苹果登录
                        break;
                    case ASAuthorizationAppleIDProviderCredentialNotFound:
                        // 未登录授权,直接弹出登录页面,引导用户登录
                        break;
                    case ASAuthorizationAppleIDProviderCredentialTransferred:
                        // 授权AppleID提供者凭据转移
                        break;
                }
            }];
        }
    }
    return YES;
}

3.2 Sever侧

基于上面流程图,Sever侧校验Token有效性的方式有两种:

方式一:基于授权码的后端验证

后端在收到客户端传递的包含token的信息后进行验证

方式二:基于JWT验证原理

token被解密后分为三个部分

signature: 用于验证JWT的签名

Token验证原理:

因为idnetityToken使用非对称加密 RSASSA【RSA签名算法】 和 ECDSA【椭圆曲线数据签名算法】,当验证签名的时候,利用公钥来解密Singature,当解密内容与base64UrlEncode(header) + “.” + base64UrlEncode(payload)的内容完全一样的时候,表示验证通过。

防止中间人攻击原理:

该token是苹果利用私钥生成的一段JWT,并给出公钥我们对token进行验证,由于中间人并没有苹果的私钥,所以它生成出来的token是没有办法利用苹果给出的公钥进行验证的,确保的token的安全性。

4 总结

目前使用的是基于授权码的后端验证方式,每次收到客户端登录请求后都会像苹果服务器发送post请求来验证,导致受网络影响较大。如果改成第一种方式后,除了获取公钥外不再依赖网络请求,可降低网络异常情况带来的损失。但是服务端要定期刷新公钥,防止公钥变化带来的验证失败

5 参考文档

developer.okta.com/blog/2019/0…

developer.apple.com/cn/sign-in-…

developer.apple.com/documentati…

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像
来说点什么吧!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容