一键提升账户安全性
One-tap account security upgrades
2020年6月24日
一句话判断
iOS 14 让「升级到 Sign in with Apple」变成了一键操作——如果你的 app 之前用邮箱+密码注册,现在可以用 ASAuthorizationAppleIDProvider 的 credential 密集合让用户一键关联 Apple 账号,大幅降低安全风险和密码管理负担。
这场 Session 讲了什么
这场 Session 专注于如何在现有 app 中引导用户从传统认证方式(邮箱密码、社交登录)升级到 Sign in with Apple,以及如何利用 Apple 的安全特性提升账户安全。
核心内容包括:使用 ASAuthorizationAppleIDProvider 实现一键账户关联、利用 ASAuthorizationPasswordProvider 自动填充已保存的密码、如何检测 Apple ID 凭证状态变化(用户撤销授权时及时处理)、以及如何在服务端验证 Apple ID Token。
Session 还介绍了 iOS 14 的新功能:当用户在一个网站或 app 上使用 Sign in with Apple 时,系统会检查该用户的邮箱是否出现在已知的数据泄露中,如果发现风险会主动提醒用户更换密码。
值得深挖的点
Credential 密集与一键关联
iOS 14 新增的「密码密集」(Credential Density)概念是指:当系统检测到你的 app 同时支持 Sign in with Apple 和传统密码登录时,会在键盘上方的 QuickType bar 中同时展示两种选项。用户可以选择 Sign in with Apple 来关联已有账号,而不是重新注册一个新账号。这个「关联」流程是你需要在 app 中实现的:检测到同一邮箱的已有账号后,把 Apple ID 绑定到这个账号上。
服务端凭证状态监控
用户可能在系统设置中撤销了对你的 app 的 Sign in with Apple 授权。你的服务端需要定期调用 Apple 的 Token Revocation API 来检查 sub(用户唯一标识)的撤销状态。一旦发现撤销,应该让 app 回退到其他认证方式。
代码片段
import AuthenticationServices
// 一键关联:引导用户用 Sign in with Apple 关联已有账号
class AccountUpgradeManager: UIViewController {
func upgradeToSignInWithApple() {
let appleIDProvider = ASAuthorizationAppleIDProvider()
let request = appleIDProvider.createRequest()
request.requestedScopes = [.fullName, .email]
let controller = ASAuthorizationController(authorizationRequests: [request])
controller.delegate = self
controller.performRequests()
}
}
extension AccountUpgradeManager: ASAuthorizationControllerDelegate {
func authorizationController(controller: ASAuthorizationController,
didCompleteWithAuthorization authorization: ASAuthorization) {
guard let credential = authorization.credential as? ASAuthorizationAppleIDCredential else { return }
let userIdentifier = credential.user
let email = credential.email
let identityToken = credential.identityToken
// 将 Apple ID 关联到已有账号
linkAppleID(toExistingAccount: userIdentifier, email: email, token: identityToken)
}
func authorizationController(controller: ASAuthorizationController,
didCompleteWithError error: Error) {
print("Sign in with Apple 失败: \(error)")
}
}
// 检查 Apple ID 授权状态
func checkAppleIDStatus(userIdentifier: String) {
let provider = ASAuthorizationAppleIDProvider()
provider.getCredentialState(forUserID: userIdentifier) { state, error in
switch state {
case .authorized:
// 授权有效,正常使用
break
case .revoked:
// 用户已撤销授权,需要重新登录或使用其他认证方式
self.handleRevokedAuthorization()
case .notFound:
// 用户 ID 不存在,可能已注销
self.handleNotFound()
default:
break
}
}
}
// 在 app 启动时检查
func applicationDidBecomeActive(_ application: UIApplication) {
if let appleUserID = UserDefaults.standard.string(forKey: "appleUserID") {
checkAppleIDStatus(userIdentifier: appleUserID)
}
}
最佳实践
- 在用户已登录后提示升级。不要强迫用户立即切换到 Sign in with Apple。在设置页面或账户安全页面提供一个「使用 Apple 登录以提升安全性」的入口,让用户主动选择。
- 关联流程要处理邮箱不一致的情况。用户可能用 A 邮箱注册了账号,但 Sign in with Apple 的隐藏邮箱是 B 邮箱。关联时要允许用户手动确认是否是同一个账号。
- 服务端定期检查撤销状态。苹果会在用户撤销授权后的 24 小时内更新状态。建议每天至少检查一次活跃用户的 Apple ID 状态。
还有什么值得关注
- Sign in with Apple 的 hidden email 功能可以让用户不暴露真实邮箱,你的 app 通过苹果提供的代理邮箱联系用户。
- iOS 14 的密码安全监控(Security Recommendations)会检测已保存密码是否出现在数据泄露中,并在设置 app 中提醒用户。
- 对于 Web 端,Sign in with Apple 现在支持通过 JavaScript API 直接调用,不需要加载 Apple 的 JS SDK。