iOS 13 苹果帐号登录与后台验证相关

简介

在WWDC 2019,苹果推出了Sign In with Apple这一iOS 13的新特性,用户能够直接利用苹果ID登录应用,免去了输入邮箱、密码,验证登录邮箱等繁琐的步骤。同时Sign In with Apple提供了跨平台特性和安全性的提升。ios

另外一方面它也提出了新的审核要求,在新的要求中提到但凡包含了第三方登陆的应用,则一样须要适配Sign In with Apple,不然会有审核风险:git

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.github

另外使用Sign In with Apple须要用户开启了两步认证,若是没有开启则会在第一次使用时提示开启,不开启将没法使用web

如何接入 Sign In with Apple

1. 项目配置

添加Sign in with Applecapability算法

并在项目中加入AuthenticationServices.framework便可。当须要使用时,须要在文件中添加<AuthenticationServices/AuthenticationServices.h>引用。api

2. 添加内置的登陆按钮

登陆按钮可使用苹果推荐的按钮ASAuthorizationAppleIDButton,具体的设计样式能够参看这里,大体的样式以下:数组

注意:安全

  • 内置的登陆按钮须要放在显眼的位置,没有强调必定要放在首位,可是提出不能让用户滚动后才看到这一个按钮。
  • 内置的登陆按钮的大小和圆角是能够自行调整的,可是大小有最大和最小的限制。
  • 没有强调必定要使用内置的登录按钮,可是在设计指南上指出最好使用样式相近的设计。

处理登陆事件

3.1 建立请求

3.1.1 新用户登陆

在新用户点击内置的登陆按钮,指望使用苹果ID进行注册和登陆时,咱们须要使用ASAuthorizationAppleIDProvider来建立一个ASAuthorizationAppleIDRequest请求,在这个请求中,咱们能够配置一个ASAuthorizationScope数组,来规定须要用户提供什么样的信息,目前ASAuthorizationScope仅包含两个:bash

  • ASAuthorizationScopeEmail: 须要用户提供电子邮件地址
  • ASAuthorizationScopeFullName: 须要用户提供姓名

须要注意的是,须要提供电子邮件时,用户是能够选择隐藏真实的邮件地址,这样获取到的邮件地址是这样的:服务器

r45N934br1@privaterelay.appleid.com

该邮箱收到的邮件会转发到用户真实的邮箱上。另外须要提供姓名时,用户是能够对姓名进行修改的,并且是任意修改。

在用户填写完姓名与选择是否隐藏邮箱后,便可以输入苹果ID的密码,并自动完成注册过程,若是无网络会没法继续,停留在在这个页面

代码实例:

// 建立请求

ASAuthorizationAppleIDProvider *appleIDProvider = [ASAuthorizationAppleIDProvider new];
ASAuthorizationAppleIDRequest *request = appleIDProvider.createRequest;
[request setRequestedScopes:@[ASAuthorizationScopeFullName,ASAuthorizationScopeEmail]];
    
复制代码

3.1.2 旧用户登陆

若是咱们的APP用户以前已经登录过,而且在keyChain上保存了用户名和密码时,能够同时使用ASAuthorizationAppleIDProviderASAuthorizationPasswordProvider来建立请求

这种方式是针对用户已经使用帐号密码登陆过该app,而且已经将他们保存到keyChain中的状况,因为对我如今项目目前的状态来讲意义不大,因此不在本文进行讨论。

3.2 发起请求

发起请求须要用到ASAuthorizationController,它能够同时发起多个Provider的请求。

代码实例:

// 发起请求

ASAuthorizationController *controller = [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[request]];
controller.delegate = self;
controller.presentationContextProvider = self;
[controller performRequests];

复制代码

在发起请求后就会出现Sign In with Apple的UI,在用户完成了登陆等操做后会返回请求结果由咱们app进行处理。

3.3 处理请求结果

ASAuthorizationController在其中提供了ASAuthorizationControllerDelegate代理,用于请求结果的回调,代理提供了两个代理方法:

成功回调:

    • (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization

失败回调

    • (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithError:(NSError *)error

在成功的回调中,咱们可以获取一个ASAuthorization对象,这个对象有providercredential这两个属性,其中provider属性可以让咱们知道是哪一类的Provider发起的请求,而credential则是苹果帐号登陆结果的一个认证。

在“新用户登陆”的状况下,返回的credentialASAuthorizationAppleIDCredential,而“旧用户登陆”的状况下,则返回ASPasswordCredential

咱们侧重于ASAuthorizationAppleIDCredential属性的解析:

  • User ID: 苹果用户惟一标识符,它在同一个开发者帐号下的全部 App 下是同样的,咱们能够用它来与后台的帐号体系绑定起来(相似于微信的OpenID)。
  • Verification Data: 包括identityToken, authorizationCode。用于传给开发者后台服务器,而后开发者服务器再向苹果的身份验证服务端验证本次受权登陆请求数据的有效性和真实性。
  • Account Information: Name, verified email,苹果用户信息,包括全名、邮箱等。
  • Real User Indicator: 用于判断当前登陆的苹果帐号是不是一个真实用户,取值有:unsupportedunknownlikelyReal

代码实例:

- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization {
		//Sign with Apple 成功
		if ([authorization.credential isKindOfClass:[ASAuthorizationAppleIDCredential class]]) {
    		//此时为使用Sign With Apple 方式登陆
  			
			ASAuthorizationAppleIDCredential *credential = authorization.credential;
  			NSString *userID = credential.user;
  			NSString *fullname = credential.fullName;
  			NSData *token = credential.identityToken
  			
  			//继续进行客户端后台登陆验证
    }
}
复制代码

3.4 与服务器验证数据

时序图

总体流程与普通的第三方登陆十分类似,一样须要获取用户ID与token,交给后台验证本次登陆的有效性。

验证流程相关

  1. 步骤1与2在客户端内完成,客户端选择使用ASAuthorizationAppleIDProvider来完成登陆,若是登陆成功,苹果将会返回以下数据:
  • User ID: 苹果用户惟一标识符,它在同一个开发者帐号下的全部 App 下是同样的,咱们能够用它来与后台的帐号体系绑定起来(相似于微信的OpenID)。
  • Verification Data: 包括identityToken, authorizationCode。用于传给开发者后台服务器,而后开发者服务器再向苹果的身份验证服务端验证本次受权登陆请求数据的有效性和真实性。
  • Account Information: 苹果用户信息,包括全名、邮箱等,登陆时用户能够选择隐藏真实的邮件地址和随意修改姓名。
  • Real User Indicator: 用于判断当前登陆的苹果帐号是不是一个真实用户,取值有:unsupportedunknownlikelyReal
  1. 步骤3与4中,客户端会把identityToken, authorizationCode, userID这三个参数传给服务器,用于验证本次登陆的有效性。

其中identityToken是一个通过签名的JSON Web Token(JWT),它包含了:

它分为了三个部分:

  • header: 包括了key id 与加密算法
  • payload:
    • iss: 签发机构,苹果
    • aud: 接收者,目标app
    • exp: 过时时间
    • iat: 签发时间
    • sub: 用户id
    • c_hash: 一个哈希数列,做用未知
    • auth_time: 签名时间
  • signature: 用于验证JWT的签名

服务端在获取客户端发出的identityToken后,须要进行以下步骤:

  1. 须要逆向构造过程,decode出JWT的三个部分
  2. appleid.apple.com/auth/keys中获取公钥,并将公钥转换pem对JWT进行验证
  3. identityToken经过验证,则能够根据其payload中的内容进行验证等操做

token验证原理:

由于idnetityToken使用非对称加密 RSASSA【RSA签名算法】 和 ECDSA【椭圆曲线数据签名算法】,当验证签名的时候,利用公钥来解密Singature,当解密内容与base64UrlEncode(header) + "." + base64UrlEncode(payload)的内容彻底同样的时候,表示验证经过。

防止中间人攻击原理:

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

4. 处理 Apple ID 登陆状态变化

用户利用Apple ID进行登陆,因此应该对ID退出登陆等状况进行处理。另外用户在利用Apple ID登陆后,能够在设置页面删除曾经登陆过的应用,相似于解除绑定的操做,这时应用也须要作对应处理。

苹果提供了一个快速的API来让咱们查询用户的Apple ID状态:

- [ASAuthorizationAppleIDProvider getCredentialStateForUserID:completion:]
复制代码

这个接口利用在登陆时获取的userID,可以快速返回账号状态:

  • authorized: 已认证
  • notFound: 用户可能还没有将账号与Apple ID绑定
  • revoked: 帐号已经注销

这个方法应该在启动时与应用返回前台时调用,确保帐号状态可以及时更新。

总结

  • 做为一种相似于三方登陆的登陆方式,后台方面须要关注的是登陆状态的验证帐号和apple userID绑定的逻辑。
  • 苹果帐号切换、注销等状态会在客户端内处理,并在状态发生变化时登出账号。

另外苹果在与后台验证一块的文档过于语焉不详,web端与app端的验证流程也有十分大的区别,让人头大。

更多内容能够关注个人博客

参考文档

相关文章
相关标签/搜索