大多数浏览器和
Developer App 均支持流媒体播放。
-
优化“通过 Apple 登录”体验
了解如何运用“通过 Apple 登录”,在您的 App 中提供安全而快速的身份验证。我们将向您介绍如何将基于密码的帐户升级到安全的一键登录凭证,并探索如何在您的 App 中无缝处理对用户会话的更改。我们还将帮助您在网页和其他平台上使用“通过 Apple 登录”。为能更好地理解此讲座,我们建议您先对“通过 Apple 登录”和 REST API 进行基本了解。此外,对 JavaScript 的了解也将很有帮助。
资源
相关视频
WWDC22
WWDC20
-
下载
Ram: 大家好 我是 Ram 是客户体验团队的一名工程师 我将和我的同事 Patrick 一起 谈谈如何为您的 App 增强 通过 Apple 登录 体验 自从 iOS 13 系统引入了 通过 Apple 登录 之后 人们就喜欢上了这种快速 简单的 账户设置和登录功能 只需几行代码 您就可以 一键快速设置账户 无需填写任何表格或密码 每个 通过 Apple 登录 账户 都会受到强大的双因素认证保护 该认证已被用于保护用户的 Apple ID 如果您需要与您的用户交流 通过 Apple 登录 会为您 提供一个可用的 电子邮件地址 无需额外验证 通过 Apple 登录 还提供了 一个指示器 显示用户真实存在的可能性有多大 这可以帮助您打击诈骗 通过 Apple 登录 可以 在任何地方使用 包括您在工作和学校使用的 管理式 Apple ID 要了解更多关于如何将您的 App 与工作和学校帐户集成的信息 请查看讲座 “Discover Sign in with Apple at Work & School“ 在本期讲座中 我们将讨论如何增强和简化您的 通过 Apple 登录 体验 首先 我将谈一谈 如何通过检查 App 中的 现有凭证来防止帐户重复 接下来 我将深入谈谈 Apple ID 凭证 然后 我将讨论一些 可以监视凭证更改的方法 并讨论如何处理帐户删除等情况 最后 Patrick 将谈一谈 如何将 通过 Apple 登录 与网络和其他平台结合 让我们开始吧 与传统的基于用户名和密码的 认证方式相比 通过 Apple 登录 是一个 方便而安全的选择 但您的用户仍然可以 使用密码解锁的账户 如果您的用户已经有了一个 可以使用的账户 那么不为您的 App 创建第二个账户就很重要 我将探讨如何在登录时引导用户做出 正确的决定
这是 Juice 一个使用 通过 Apple 登录 的样例 App 您可以在这个视频的相关链接中 找到它的源代码
您可以使用传统的电子邮件 和密码登录 Juice 也可以使用 通过 Apple 登录 如果您的用户已经拥有 这些凭证中的任何一个 那么帮助他们登录到正确的帐户 就是您的责任 首先 请确保实现密码自动填充 以便在登录屏幕的键盘上 显示现有的密码凭证
这样 用户只需点击一次 就可以实现自动填充凭证
另外 您应该帮助您的用户 将基于密码的账户 升级到 通过 Apple 登录 一旦升级 您的用户将获得一个 内置安全功能的账户 他们也少了一个需要记住的密码 这是通过帐户身份验证修改扩展 来实现的 基于扩展的 API 为您的用户 提供了无缝体验 以升级他们使用 通过 Apple 登录 来登录的方式
要想了解更多关于 为用户的账户提供安全升级的信息 请查看文档 “Get the most out of 通过 Apple 登录” 和“One-tap account security upgrades”
除了提供密码自动填充之外 您还可以更进一步 在 App 启动时 立即提供现有的凭证 这样 您的用户甚至可以在 看到登录屏幕之前 就使用正确的帐户进行登录 验证服务 API 在这方面非常灵活 认证服务除了允许用户 创建 通过 Apple 登录 的凭证外 API 还可以提供现有凭证 包括基于密码的凭证
采用这种方法真的很容易 让我带您看一些实现这一点 所用的代码 如果您已经在使用 Authentication Services API 那么您应该对这段代码非常熟悉
首先创建一个 ASAuthorizationController 实例 并在授权请求数组中包含 ASAuthorizationAppleIDProvider 和 ASAuthorizationPasswordProvider 然后您需要设置一个委托 和一个对象来帮助呈现接口 最后 您需要在授权控制器上 使用 preferimmediateyavailablecredentials 选项 来调用 performRequests 这在 iOS 16 上是新选项 它告诉系统 您只需要 设备上立即可用的凭证 它是专门在 App 发布时调用的
如果您想支持以前的 iOS 版本 您可以使用 performRequests 当您这样做时 您将看到一个现有凭证的列表 现在 您的用户可以选择 现有的 通过 Apple 登录 凭证 或现有的密码凭证 在用户选择了一个凭证之后 系统将在 ASAuthorizationController 委托上 调用 didCompleteWithAuthorization 如果用户选择了 通过 Apple 登录 账户 您将继续使用 AppleIDCredential 如果用户选择了基于密码的帐户 则使用返回的 passwordCredential 进行登录 如果用户没有现有的凭证 API 将不会显示欲创建 通过 Apple 登录 帐户的用户 相反 系统会调用 didCompleteWithError 在这些场景中 您应该返回到显示标准登录流 顺便一提 同样的 Authentication Services API 也可以无缝用于万能钥匙 要了解更多关于万能钥匙 一种替代密码的 新一代身份验证技术的信息 请查看课程 “Meet passkeys” 只需几行代码 您就可以充分利用 登录体验 现在 您可以帮助您的用户 选择正确的帐户了 这样就有望防止在您的系统中 创建重复帐户
接下来 我想带您 深入了解一下 Apple ID 凭证
如您所知 在使用 通过 Apple 登录 成功授权后 您得到的响应是一个 ASAuthorizationAppleIDCredential 对象 它包含像用户 fullName 电子邮件 realUserStatus identityToken 和 authorizationCode 这样的值 我将简要地介绍它们 User 是唯一且稳定的标识符 它是在您的开发者团队的 所有 App 中 都相同的标识符
使用这个可以唯一标识系统中的用户 您应该只在需要的时候 要求 fullName 如果请求了 您的用户可以共享 他们想共享的任何名称 如果您想和您的用户交流 您应该请求电子邮件 当被请求时 您的用户有两种 共享电子邮件地址的选择 一种选择是共享与 Apple ID 关联的邮箱 另一种选择是使用 “隐藏我的邮箱”功能 这会创建一个隐藏的电子邮件地址 转接到他们的收件箱 它是双向中继的 所以它也可以处理回复
无论选择哪一种方式 邮箱地址都已经 经过 Apple 公司的验证 可以使用 此外 并不是所有帐户 都有关联的电子邮箱 所以要准备好处理 即使您请求了电子邮件 也没有电子邮件值的情况
RealUserStatus 是一个关于 用户真实可能性的 高置信度指标 它是在保护用户隐私的同时 通过使用设备时的机器学习 帐户历史记录和硬件认证来计算的 realUserStatus 有三种类型 “可能真实”意味着用户 看起来是一个真实的人 要为这个用户提供最好的体验 例如跳过 CAPTCHA 这样的 额外的欺诈验证检查 “未知”是指系统还没有确定 用户是否是真人 就像信任任何需要额外验证步骤的 信息有限的帐户一样信任此用户 用户仍可能是真实的 所以不要阻止他们 使用您的 App
最后 “不受支持”意味着 系统不具备 这种判断能力 我应该指出 像 fullName 电子邮件和 realUserStatus 这样的属性 只在第一次创建帐户时返回
后续登录时不会返回这些值 所以要确保安全地缓存 像 fullName 和电子邮件这样的属性 直到您可以验证 您的系统中已经创建了一个帐户
identityToken 是一个 JSON web 令牌 包含了 App 服务器需要的 大部分数据 包括用户信息 这是一种行业标准验证方法 JSON web 令牌或称 JWT 由三部分组成 base-64 URL 编码 header base-64 URL 编码有效载荷 以及来自 Apple 的签名 您应该用 Apple 的公钥验证签名 以确保响应没有被篡改 并且确实来自 Apple ID 服务器 应用服务器 检查令牌的可用性同样重要 解码有效载荷之后 您应该验证发布者是否是 appleid.apple.com 验证受众字段是您的 App 的 包标识符 然后确保过期时间戳 大于当前时间 这样您就知道令牌是有效的 主题将是您的用户标识符 如果您要求用户的电子邮件地址 它也将包括在内 您还可以找到 realUserStatus 该值为 0 表示“不支持” 1 表示“未知” 2 表示“可能真实” 最后 验证 nonce 是否与 创建授权请求之前生成的 nonce 相同
要了解更多关于 nonce 以及如何保护您的授权过程 以减轻重放攻击的信息 请查看讲座 “Get the most out of 通过 Apple 登录”
AuthorizationCode 是一个 短时的一次性令牌 您可以提供 Apple ID 服务器 来交换刷新令牌 如果您的系统已经使用了 OAuth 2.0 这样的开放标准 那么这对您来说可能很熟悉 为了生成一个刷新令牌 您应该向 auth/token 端点 发送一个 post 请求 您要传递客户端 ID 和客户端机密 以及刚刚接收到的授权代码 关于如何创建客户端机密的详细描述 可以在 Apple Developer 文档中找到 在响应中 您将获得一个刷新令牌 一个访问令牌 和一个与您之前收到的令牌类似的 新身份令牌 如果您有过期的访问令牌 您可以使用刷新令牌 通过相同的端点 获得一个新的访问令牌 您还可以继续使用相同的刷新令牌 直到它失效为止 如果令牌验证失败 或用户会话周围发生更改 刷新令牌可能会失效
谈到用户会话 接下来 我将谈一谈如何处理和监视 凭证状态的变化 在验证身份令牌之后 您的 App 要负责管理用户会话
有多种场景可以触发用户会话更改 例如 用户可以在设置中 停止在您的 App 中使用 Apple ID 或者他们可能已经注销了设备 要优雅地处理会话更改 请调用 ASAuthorizationAppleIDProvider 上的 getCredentialState(forUserID:) 建议您在 App 启用时 或者在任何您想要检查状态的地方 调用这个 API 您还应该观察 credentialRevokedNotification 以便您的 App 在证书被撤销时 得到通知 如果您观察到状态的任何变化 您应该假设一个不同的用户已经登录 并将当前用户退出 App 如果您有一个 App 服务器 您应该订阅服务器到服务器通知 您的服务器将收到关于您的用户 和他们的帐户的重要更新 在以下场景中 通知将会发送到 App 的每个组 当用户禁用或启用他们的 邮件转发首选项时 当用户停止在您的 App 中 使用他们的 Apple ID 时 或者当用户永久删除 他们的 Apple ID 时 要开始接收通知 您应该首先在 Apple Developer 门户中 注册一个端点 URL 所有事件都会到达相同的端点 URL 事件以 Apple 签名的 JSON web 令牌的形式发送 如果邮件转发被禁用 您将在 JWT 的有效载荷中 收到一个禁用邮件的事件
当用户停止在您的 App 中 使用他们的 Apple ID 时 您会收到一个同意撤销事件 当您收到此事件时 重要的是 使任何活动用户会话无效
如果用户删除了他们的 Apple ID 您会收到一个账户删除事件 同样 请确保 使任何活动用户会话无效 并根据您的流程更新他们的帐户
现在我想把重点放在删除账户上 账户是我们身份的一部分 我们用它们来管理一些 最个人和隐私的数据 有人可能会想要删除他们的帐户 您需要在您的 App 中支持这一点
您应该提供一种从您的 App 中 初始化帐户删除的方法 管理整个删除过程 是您的责任
如果您有一个存储用户信息的 App 服务器 通常情况下 App 会通知服务器 删除用户帐户 现在 您可以在删除过程中 加入 通过 Apple 登录 了 实现这一点需要使用一个新的 您的服务器可以使用的 REST 端点来删除 与您的 App 相关联的帐户 让我简要介绍一下这个 API 为了删除帐户 您必须为用户提供有效的 刷新令牌或有效的访问令牌 如果这两个令牌都没有 可以使用 auth/token 端点生成 一旦您有了这两个令牌之一 就可以使用带有所需参数的 auth/revoke 端点 使用刷新令牌时 将令牌类型设置为 REFRESH_TOKEN
如果要使用访问令牌进行删除 请将令牌类型设置为 ACCESS_TOKEN 如果您获得了一个成功响应 令牌和用户的活动会话 将立即失效
一旦被删除 用户返回到您的 App 并使用 通过 Apple 登录 时 将拥有与他们第一次使用 App 创建帐户时相似的体验
接下来 我会退出 让我的同事 Patrick 继续探讨您可以如何在网络 和其他平台上 使用 通过 Apple 登录 的问题
Patrick: 谢谢 Ram 人们喜欢 通过 Apple 登录 在所有 Apple 平台上 无缝运行的方式 但它不止于此 通过 Apple 登录 也可以在网络 和其他平台上无缝运行 让我们来讨论一下 如何增强您的 通过 Apple 登录 体验 以支持网络和其他平台
Ram 之前介绍过一款 iOS App 叫做 Juice 我们希望通过扩展到网络 将 Juice 带给更多的用户 让我们从讨论如何将 相似的 App 分组开始
建议您将相关的 App 组合在一起 以精简用户体验 通过将相关的 App 分在一组 您的用户只需要同意一次 就可以与您的 App 共享他们的信息
例如 您的 App 可能在 iOS 和 macOS 上可用 但在每个平台上会使用 不同的捆绑标识符 建议您将这些 App 分在一组 当使用 通过 Apple 登录 时 您的用户会看到您设置为主 App 的 App Icon 让我们来看看 如何通过配置一个服务 ID 来支持在您的网站上 使用 通过 Apple 登录 首先 登录到 Apple Developer Portal 并导航到 “Certificates, Identifiers & Profiles”
选择 Services IDs 旁边的单选按钮 然后单击 “继续”
输入您的服务描述
为您的服务输入唯一标识符 然后单击继续
单击 通过 Apple 登录 旁边的复选框 然后单击配置按钮 在 Web Authentication Configuration 界面的 下拉菜单中选择 Primary App ID
接下来 输入您将用于 支持 通过 Apple 登录 的 网站的域名和子域名 最后 输入一个重定向 URL 让 Apple 在授权成功后将您的用户 重定向到您的 App 或网站 就是这样 您已经配置好了一个服务 ID 以在您的网站上 支持 通过 Apple 登录 您需要一个按钮 用于向用户显示 您的网站支持 通过 Apple 登录 Apple 提供了一个 高度可配置的按钮 API 来生成 通过 Apple 登录 的按钮图像
使用这个在您的 App 或网站 自定义并嵌入 您的按钮选择 通过 Apple 登录 JS 是一个 简单的 Javascript framework 它使 通过 Apple 登录 在网络上更容易集成 在您的 App 或网站中 首先要包含 通过 Apple 登录 Javascript framework 这个简单的 API 将允许您 对用户进行身份验证 并获得不同的 asset 比如 只需一个简单的 DIV 就可以创建的 通过 Apple 登录 按钮 您也可以通过修改按钮的属性 自定义按钮以适应您的 App 或网站
例如 在当前属性中 您会看到一个白色的 通过 Apple 登录 按钮 它有边界和默认的角半径 通过更改数据颜色属性 我们就可以 为按钮选择不同的背景颜色 如果我们将数据类型更改为“继续” 按钮文本将更新为显示 “继续使用 Apple”
或者 您可以通过将数据模式属性 设置为仅限登录 来创建仅限登录按钮 通过 Apple 登录 Javascript Button API 提供了更多可定制的属性 您可以参考 通过 Apple 登录 按钮资源 来轻松配置这些选项
如果您偏好使用 REST API 来生成 通过 Apple 登录 按钮 您可以使用 Apple ID 按钮端点之一 来生成一个按钮 中间对齐 左对齐和徽标按钮 分别有独立的端点 您可以通过查询参数来自定义该按钮 在这个请求示例中 我自定义了一个带边框的 白色的 通过 Apple 登录 按钮 我收到了一个 以 PNG 图像作为自定义按钮的响应 现在您已经自定义了 通过 Apple 登录 按钮 是时候验证您的用户了 您需要向 Apple 发送一个 带有所需参数的授权请求 这些是成功登录用户 所需的参数
因为您已经在 Apple 平台上 使用了 通过 Apple 登录 所以您应该对这些参数非常熟悉
首先 我们需要设置客户端 ID 这将是您在 Apple Developer Portal 上 为您的 App 或网站 创建的服务 ID
接下来 如果您的 App 或网站 需要电子邮件或名称 填写 “范围” 参数 如果请求多个范围 请使用空格来分隔每个范围 只请求需要的数据是很重要的
您将在重定向 URI 参数处 添加您之前在 Apple Developer Portal 上注册的 URL 并通知 Apple 将用户导向 您的网站上的哪一处
您还可以添加一个状态和 nonce 来保护您的请求
最后 使用 use Pop up 参数 您可以选择在一个单独的弹出窗口 显示登录屏幕 或者将现有窗口 重定向到 Apple 登录网站 如果有人在使用 Safari 浏览器 他们会看到这样一个本机屏幕 为他们提供 登录您的网站的一流体验 在 Apple ID 服务器处理授权请求之后 您将收到一个 包含授权结果的 DOM 事件 要处理成功响应 可以为 AppleIDSignInOnSuccess 添加一个事件监听器
要处理失败响应 可以为 AppleIDSignInOnFailure 添加一个事件监听器
如果授权成功 您将收到一个响应 其中包含授权代码 身份令牌 如果请求了 还会有用户信息 这与您在 Apple 平台上 已经习惯的响应类似 如果您希望 使用 REST API 直接与 Apple ID 服务器集成 您可以用所需的参数 将授权请求定向到授权端点 如果授权成功 您将得到一个包含授权代码 身份令牌 和用户信息的响应 这与您在 Apple 平台上 已经习惯的响应非常相似 就是这样 您已经成功地在您的网站上 采用了 通过 Apple 登录 最后 我想强调一些在实现 通过 Apple 登录 时 需要牢记的重要事项
除非您的 App 需要大量 基于账户的功能 让人们无需登录 就可以使用您的 App 例如 您可以允许用户 使用 Apple Pay 购买商品 然后让他们可以选择在购买完成后 将这次购买与账户绑定 通过把用户名和密码认证切换到 通过 Apple 登录 为现有用户提供 升级帐户安全性的能力 如果您只需要一个唯一的标识符 来识别用户 不要收集姓名或电子邮件 如果您确实用 Sign In with Apple 收集了邮箱地址 请确保您尊重了用户的选择 您不应该提示输入额外的邮箱地址
在所有提供您的 App 或网站的平台上 支持使用 Sign In with Apple 是很重要的 您的用户可能会使用多个平台 他们会希望在任何地方 都能使用 Sign In with Apple 我们非常期待看到您会在您的 App 中 使用 Sign In with Apple 做些什么 我们期待您的反馈 感谢收看 请享受余下的 WWDC 之旅吧
-
-
4:03 - Presenting Existing Credentials
// Requesting both Sign in with Apple and password-based accounts. import AuthenticationServices let controller = ASAuthorizationController(authorizationRequests: [ ASAuthorizationAppleIDProvider().createRequest(), ASAuthorizationPasswordProvider().createRequest() ]) controller.delegate = self controller.presentationContextProvider = self if #available(iOS 16.0, *) { controller.performRequests(options: .preferImmediatelyAvailableCredentials) } else { controller.performRequests() }
-
5:14 - ASAuthorizationControllerDelegate Implementation
// ASAuthorizationControllerDelegate func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) { switch authorization.credential { case let appleIDCredential as ASAuthorizationAppleIDCredential: // Sign the user in with Apple ID credential. // ... case let passwordCredential as ASPasswordCredential: // Sign the user in with password credential // ... } } func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) { // No credential found. Fall back to login UI. }
-
12:00 - Checking Credential State
// Check User Credentials on app launch let appleIDProvider = ASAuthorizationAppleIDProvider() appleIDProvider.getCredentialState(forUserID: "currentUserIdentifier") { (credentialState, error) in switch(credentialState){ case .authorized: // Found valid Apple ID credential case .revoked: // Apple ID credential revoked. Log the user out. case .notFound: // No credential found. Show login UI. case .transferred: // Team is transferred } }
-
12:18 - Register for Revocation Notification
// Register for revocation notification let notificationName = ASAuthorizationAppleIDProvider.credentialRevokedNotification NotificationCenter.default.addObserver(self, selector: #selector(signOut(_:)), name: notificationName, object: nil)
-
17:55 - Sample HTML and Javascript Implementation
// Embed Sign in with Apple JS <html> <body> <script type="text/javascript" src="https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js"></script> <div id="appleid-signin" data-color="white" data-border="true" data-type="sign in"/> <script type="text/javascript"> AppleID.auth.init({ clientId : '[CLIENT_ID]', scope : '[SCOPES]', redirectURI : '[REDIRECT_URI]', state : '[STATE]', nonce : '[NONCE]', usePopup : true }); </script> </body> </html>
-
18:28 - White Sign in with Apple Button
<div id="appleid-signin" data-color="white" data-border="true" data-type="sign in"/>
-
18:38 - Black Sign in with Apple Button
<div id="appleid-signin" data-color="black" data-border="true" data-type="sign in"/>
-
18:44 - Black Continue with Apple Button
<div id="appleid-signin" data-color="black" data-border="true" data-type="continue"/>
-
18:50 - Black Logo Only Button
<div id="appleid-signin" data-color="black" data-border="true" data-mode="logo-only"/>
-
19:47 - Sample HTML and Javascript Implementation
// Embed Sign in with Apple JS <html> <body> <script type="text/javascript" src="https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js"></script> <div id="appleid-signin" data-color="white" data-border="true" data-type="sign in"/> <script type="text/javascript"> AppleID.auth.init({ clientId : '[CLIENT_ID]', scope : '[SCOPES]', redirectURI : '[REDIRECT_URI]', state : '[STATE]', nonce : '[NONCE]', usePopup : true }); </script> </body> </html>
-
21:11 - Handle DOM Response
// Listen for authorization success. document.addEventListener('AppleIDSignInOnSuccess', (event) => { // Handle successful response. console.log(event.detail.data); }); // Listen for authorization failures. document.addEventListener('AppleIDSignInOnFailure', (event) => { // Handle error. console.log(event.detail.error); });
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。