WWDC2019之 Sign in with Apple

Authentication

iOS13中 authentication 的更新主要有:

  • sign in with Apple
  • password-based authentication
  • warning for weak passwords
  • OAuth sign-in
  • USB security keys on macOS

主要还是围绕 Sign in 展开:

  1. 使用 Apple ID sign in
  2. sign in 的时候利用已登陆的账号自动输入账号密码
  3. 密码太弱时的提醒

这些内容都围绕着: 安全-方便-友好 而展开的,接下来重点谈谈 sign in with Apple。

Sign in with Apple

文档中,Apple提到:

Apple does not use Sign In with Apple to profile users or their activity in apps.

对注重个人隐私的用户,这是一个非常值得期待的功能。

准备工作

在Xcode11中,开启sign in 功能,本质上是在 entitlement 文件中添加了一个key:"com.apple.developer.applesignin",它的值是字符串数组。然后在设备上确认账号,该账号必须是开启过两步验证的Apple ID。确认后,该账号就是 primary App ID。接下来,使用该 primary App ID创建私钥,并记录下该 key id。
如果有多个App的,可以创建 app group,共享 Apple ID。

实现

集成过程可以简单地分为:

  1. 添加内置(built-in)按钮
  2. 发起authentication请求
  3. 响应协议并和自己的后台通信(如果需要的话)

添加按钮:

func setUpProviderLoginView() {
    let button = ASAuthorizationAppleIDButton()
    button.addTarget(self, action: #selector(handleAuthorizationAppleIDButtonPress),for: .touchUpInside)
    self.loginProviderStackView.addArrangedSubview(button)
}

发起请求:

@objc func handleAuthorizationButtonPress() {
    let request = ASAuthorizationAppleIDProvider().createRequest()
    request.requestedScopes = [.fullName, .email]
    let pwdRequest = ASAuthorizationPasswordProvider().createRequest()
    let controller = ASAuthorizationController(authorizationRequests: [request, pwdRequest])
    controller.delegate = self
    controller.presentationContextProvider = self
    controller.performRequests()

这里,发起请求的时候,通常也希望使用密码自动填充功能,所以使用了 ASAuthorizationPasswordProvider 创建请求。
响应协议:

func authorizationController(controller _: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {

    switch authorization.credential {
    case let credential as ASAuthorizationAppleIDCredential:
        let userIdentifier = credential.user
        let identityToken = credential.identityToken
        let authCode = credential.authorizationCode
        let realUserStatus = credential.realUserStatus
        // Sign the user in using the Apple ID credential
        // Create account in your system
    case let credential as ASPasswordCredential:
        // Sign the user in using their existing password credential
    default: break
    }
}
func authorizationController(_: ASAuthorizationController, didCompleteWithError error: Error) {
// Handle error
}

处理登录状态的变化

这里有两种场景:

  1. 使用App的时候,不再使用Apple ID (stop using Apple ID with app)
  2. 在设备上退出登录(sign out of the device)
let provider = ASAuthorizationAppleIDProvider()
provider.getCredentialState(forUserID: "currentUserIdentifier") { (credentialState, error) in
    switch(credentialState){
    case .authorized:
    // Apple ID Credential is valid
    case .revoked:
    // Apple ID Credential revoked, handle unlink
    case .notFound:
    // Credential not found, show login UI
    default: break
    }
}

因为sign in with Apple本质是 OAuth,因此存在authentication 重置(revoke)的情形。这种情况下,可以:

// Register for revocation notification
let center = NotificationCenter.default
let name = NSNotification.Name.ASAuthorizationAppleIDProviderCredentialRevoked
let observer = center.addObserver(forName: name, object: nil, queue: nil) { (Notification) in
// Sign the user out, optionally guide them to sign in again
}

发送邮件给用户

使用sign in with Apple 后,如果要给用户发送信息,那么需要使用 Apple’s private email relay service。首要的,在开发者账户中配置:

Certificates, Identifiers&Profiles->More->Configure Sign In with Apple

将相关内容注册后即可,注意添加的域名需要添加 SPF DNS TXT 记录,这样才能允许苹果代替你的域名发送邮件。
这些也可以在Xcode中添加App的capability。

参考 references

Configuration
Sign in with Apple
HumanGuideline: Sign in with Apple