介绍Apple登录-Apple授权系统

哈Ha!

今年夏天,在WWDC 2019大会上,苹果推出了自己的使用Apple登录系统,并强制要求 App Store中所有使用社交媒体登录的应用程序都必须使用该系统。 使用自己的授权的教育,公司,政府和商业应用程序除外。 对于使用Apple登录,Apple提供了高质量的文档 ,在本文中,我们将使用CIAN的示例来描述如何在我们的服务中实现它。



配置苹果开发者帐户


集成工作始于设置开发者帐户。 首先,您需要为您的App ID启用“使用Apple登录”选项。 为此,请转到Apple开发者帐户中的标识符列表 ,选择必要的App ID并为其启用“使用Apple登录”选项。

现在,我们配置服务ID-Web应用程序的唯一标识符,您将需要使用Apple API访问登录。 每个应用程序ID总共最多可以创建5个服务ID。 为此,请单击用于创建标识符的按钮,选择“服务ID”,填写必填字段,然后在“使用Apple登录”字段中单击“编辑”。 将打开一个表单,供我们选择正确的主应用程序ID,指定网络域,并在成功登录后列出用于重定向的URL。 请记住,您只能输入10个返回URL:



要保存,请单击保存,继续并注册。 是的,对于任何配置更改,必须单击所有三个按钮,否则更改将不会生效。

现在,在“服务ID”列表中,选择创建的标识符,然后在“使用Apple登录”字段中再次单击“编辑”。 在打开的窗口中,网址字段旁边,我们看到两个新按钮:



苹果需要此文件来验证您的资源。 下载它并将其放在您的资源上。 立刻,这种假装对我们不起作用:当我们的管理员添加文件时,对位于其他位置的文件的重定向(302)在指定的url上起作用,Apple并未对其进行验证。 然后,我必须放置文件以通过URL直接访问(200)。 Apple成功检查文件后,该域旁边的绿色复选标记会亮起:



从标识符部分,转到“密钥”部分并创建一个新密钥。 为此,请选中“使用Apple登录”复选框,然后首先单击“配置”以检查App ID,然后单击“继续”:



在下一个屏幕上,请确保使用密钥下载文件并将其保存在安全的地方,因为离开此屏幕后,将无法下载密钥。 在同一页面上,您可以看到我们仍然需要的密钥ID:



使用Apple登录对用户有一个好处:它允许您提供伪造的电子邮件,您只能从受信任的地址向其发送邮件。 在这种情况下,需要其他配置。 打开“更多”部分,在“使用Apple登录”部分中单击“配置”,然后输入您的URL:



将“使用Apple登录”按钮添加到iOS应用。


CIAN在三个平台上工作:iOS,Android,Web。 有一个适用于iOS的本地SDK,因此授权如下所示:



要将“使用Apple登录”添加到iOS应用程序,请添加ASAuthorizationAppleIDButton按钮并在其上悬挂点击处理程序:

let appleIDProvider = ASAuthorizationAppleIDProvider() let request = appleIDProvider.createRequest() request.requestedScopes = [.fullName, .email] let authorizationController = ASAuthorizationController(authorizationRequests: [request]) authorizationController.delegate = self authorizationController.presentationContextProvider = self authorizationController.performRequests() 

除了ASAuthorizationAppleIDProvider之外,还要注意ASAuthorizationPasswordProvider,它使您可以从钥匙串中获得一堆“登录密码”。

现在,我们实现ASAuthorizationControllerPresentationContextProviding:

 func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {    return self.view.window! } 

创建一个报告成功或错误的ASAuthorizationControllerDelegate委托:

 public func authorizationController( controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization ) { guard let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential, let code = appleIDCredential.authorizationCode, let codeStr = String(data: code, encoding: .utf8) else {        // -            //           return } let email = appleIDCredential.email let firstName = appleIDCredential.fullName?.givenName let lastName = appleIDCredential.fullName?.familyName //           codeStr } public func authorizationController( controller: ASAuthorizationController, didCompleteWithError error: Error ) { //   } 

我们将接收到的authorizationCode发送到服务器,并等待后端关于系统中授权成功的响应。

我们为网络和Android实施与Apple的登录


突然,对于Android和Web,Apple不提供SDK,因此在两种情况下,您都需要打开Apple授权页面,并且过程将有所不同:



登录页面的URL如下:

 https://appleid.apple.com/auth/authorize?\ state=abvgd&\ response_type=code&\ client_id=ServiceID&\ scope=email+name&\ response_mode=form_post&\ redirect_uri=https%3A%2F%2Fcian.ru%2Fauth%2Fsome-callback%2F%3Ftype%3Dappleid 

考虑其参数:

  • client_id-上面注册的服务ID。
  • redirect_uri-通过AppleID成功进行身份验证后,将用户重定向到的URI。 设置Apple Developer时,我们在上面指定了此URI。
  • state-Apple在调用redirect_uri时将返回的用户的会话标识符,以便我们可以检查发件人。 您可以发明自己生成此参数的规则,例如,随机字符串。
  • 作用域-此参数指示需要用户提供哪些信息。 例如,如上例所示,名称,电子邮件或两者兼而有之。
  • response_type-此参数指示需要哪种形式的响应。 它可以是代码或id_token。 如果选择id_token,则需要使用response_mode参数指定它,您可以在其中指定查询,片段和form_post。

通过appleID成功进行两因素身份验证后,Apple将调用指定的redirect_uri并传递状态和代码参数:

 curl -X POST \ 'https://www.cian.ru/some-callback/?type=appleid' \ -H 'Content-Type: application/x-www-form-urlencoded' \ --data ' \ state=abvgd&\ code=12345&\ user={"name":{"firstName":"Tanya","lastName":"Sviridova"},"email":"someemail@gmail.com"}' 

在code参数中,传递了一次用户验证码,该验证码有效期为5分钟。 在状态参数中,创建授权表单时发送的会话标识符,在用户参数中,用户数据。

资料检索


在所有客户端上,要保存用户数据,您需要从Apple获得access_token。 为此,请首先请求authorization_code:

 curl -X POST https://appleid.apple.com/auth/token -d '\ client_id=some_client_id&\ code=12345&\ client_secret=jwt_part1.jwt_part2.jwt_part3&\ grant_type=authorization_code' 

在此请求中:

  • client_id表示为Web应用程序创建的ServiceID和iOS应用程序的AppID。
  • 代码-重定向或从iOS客户端转移后,我们收到的价格更高
  • 在grant_type参数中,我们达到了获得令牌的目的:授权(authorization_code)或令牌的续签(refresh_token)
  • 在client_secret参数中-基于在应用程序注册期间获得的密钥的JSON Web令牌。

您可以在Python中创建JSON Web令牌:

 claims = { 'iss': APPLEID_TEAM_ID, 'aud': 'https://appleid.apple.com', 'sub': client_id, 'iat': current_timestamp, 'exp': current_timestamp + expire_period, } headers = {'kid': 'APPLEID_KEY_ID', 'alg': 'ES256'} client_secret = jwt.encode(payload=claims, key=secret_key, algorithm='ES256', headers=headers).decode('utf-8') 

如果一切顺利,则响应中将包含以下参数:
 {  "access_token":"ufhzch",  "token_type":"Bearer",  "expires_in":3600,  "refresh_token":"some_refresh_token",  "id_token":"some_long_signed_jwt_token" } 

万岁,这是access_token。 随之而来的是refresh_token,可以在必要时对其进行更新。

用户信息存储在id_token字段中,但需要对其进行解码:
 public_key = jwt.algorithms.RSAAlgorithm.from_jwk(    json.dumps(apple_public_key) ) data = jwt.decode(    id_token,    public_key,    algorithm="RS256",    verify=True,    audience=client_id, ) 

Apple_public_key是可以从链接获取的公共密钥

解码后,我们得到:

 data = {  "iss": "https://appleid.apple.com",  "aud": client_id,  "exp": 1570379521,  "iat": 1570378921,  "sub": "  ",  "at_hash": "8ZDF6j786IQf9mA",  "email": "someemail@gmail.com",  "email_verified": "true",  "auth_time": 1570378804 } 

当用户首次通过“使用Apple登录”登录到您的服务时,电子邮件仅传输一次。 下次,只有在用户自行取消绑定应用程序时,Apple才会传输此数据。 苹果公司的这项授权不同于其他可通过API获得数据的服务,我们未找到他们计划实施类似服务的信息。

在此答案中,我们需要每次都传输的参数子和电子邮件,因此我们将它们保存在系统中并通知客户成功的授权。 利润。

初步结果


在发布具有Apple登录功能的CIAN新版本之后,在第一天的第一天,它就占了iOS 13新注册的三分之一,现在,它在所有iOS版本中都排名第二,仅次于VK。 该站点上使用AppleID的注册很少,但注册数量正在缓慢增长。 现在,我们计划通过Android应用程序上的AppleID启用授权,并查看有多少用户将以这种棘手的方式进行注册。

Source: https://habr.com/ru/post/zh-CN475062/


All Articles