Apple登录基础( iOS Swift )

6,170 阅读5分钟

示例代码

实施使用“通过 Apple 登录”进行用户认证

为 app 的用户提供一种设置帐户并开始使用相应服务的方式。

下载官方示例代码(英文)

添加“通过Apple登录”按钮

Apple登录按钮有两种方式 

1.“通过Apple登录”按钮(ASAuthorizationAppleIDButton (英文))。视图控制器还会将自身添加为按钮的目标,并传递按钮收到触控事件时要调用的操作

func setupProviderLoginView() {
    let authorizationButton = ASAuthorizationAppleIDButton()
    authorizationButton.addTarget(self, action: #selector(handleAuthorizationAppleIDButtonPress), for: .touchUpInside)
    self.view.addSubview(authorizationButton)
}

重要信息

在将“通过 Apple 登录”按钮添加到 Storyboard 时,您还必须在 Xcode 的 Identity Inspector 中将该控件的类值设置为 ASAuthorizationAppleIDButton。

2.自定义苹果登录按钮样式

请参考(苹果登录按钮设计规范

使用 Apple ID 请求授权

当用户轻点“通过 Apple 登录”按钮时,视图控制器会调用 handleAuthorizationAppleIDButtonPress() 函数,该函数会执行授权请求来获取用户的全名和电子邮件地址,从而开始认证流程。然后,系统会检查用户是否在设备上登录了 Apple ID。如果用户没有在系统级登录,app 会显示一条提醒,指引用户在“设置”中使用 Apple ID 登录。

@objc func handleAuthorizationAppleIDButtonPress() {
    let appleIDProvider = ASAuthorizationAppleIDProvider()
    let request = appleIDProvider.createRequest()
    request.requestedScopes = [.fullName, .email]
    
    let authorizationController = ASAuthorizationController(authorizationRequests: [request])
    authorizationController.delegate = self
    authorizationController.presentationContextProvider = self
    authorizationController.performRequests()
}

重要信息

用户必须启用双重认证才能使用“通过 Apple 登录”,这保证对帐户的访问是安全的。

授权控制器会调用 presentationAnchor(for:)(英文) 函数来从 app 中获取窗口,用于将“通过 Apple 登录”内容以模态表单的形式呈现给用户。

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

如果用户已在系统级使用 Apple ID 登录,则会显示该表单来介绍“通过 Apple 登录”功能,然后会显示另一个表单,让用户可以编辑帐户中的信息。用户可以编辑自己的名字和姓氏,选取另一个电子邮件地址作为联系信息,以及对 app 隐藏自己的电子邮件地址。如果用户选择对 app 隐藏自己的电子邮件地址,Apple 会生成一个代理电子邮件地址来将电子邮件转发到用户的私人电子邮件地址。最后,用户输入 Apple ID 的密码,然后点按“Continue”(继续) 以创建帐户。

处理用户凭证

如果认证成功,授权控制器会调用 authorizationController(controller:didCompleteWithAuthorization:)(英文) 委托函数,app 使用该函数将用户的数据储存在钥匙串中。

func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
    switch authorization.credential {
    case let appleIDCredential as ASAuthorizationAppleIDCredential:
        
        // Create an account in your system.
        let userIdentifier = appleIDCredential.user
        let fullName = appleIDCredential.fullName
        let email = appleIDCredential.email
        
        // For the purpose of this demo app, store the `userIdentifier` in the keychain.
        self.saveUserInKeychain(userIdentifier)
        
        // For the purpose of this demo app, show the Apple ID credential information in the `ResultViewController`.
        self.showResultViewController(userIdentifier: userIdentifier, fullName: fullName, email: email)
    
    case let passwordCredential as ASPasswordCredential:
    
        // Sign in using an existing iCloud Keychain credential.
        let username = passwordCredential.user
        let password = passwordCredential.password
        
        // For the purpose of this demo app, show the password credential as an alert.
        DispatchQueue.main.async {
            self.showPasswordCredentialAlert(username: username, password: password)
        }
        
    default:
        break
    }
}

注释

在您的实施中,ASAuthorizationControllerDelegate.authorizationController(controller:didCompleteWithAuthorization:) 委托函数应使用用户标识符中包含的数据在您的系统中创建一个帐户。

如果认证失败,授权控制器会调用 authorizationController(controller:didCompleteWithError:)(英文) 委托函数来处理错误。

func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
    // Handle error.
}

系统对用户进行认证后,app 会显示 ResultViewController,该控制器显示从框架请求的用户信息,其中包括用户提供的全名和电子邮件地址。该视图控制器还会显示“Sign Out”(注销) 按钮,并将用户数据储存在钥匙串中。当用户轻点“Sign Out”(注销) 按钮时,app 会从视图控制器和钥匙串中删除用户信息,并向用户显示 LoginViewController。

请求现有的凭证

LoginViewController.performExistingAccountSetupFlows() 函数会通过请求 Apple ID 和 iCloud 钥匙串密码来检查用户是否已有帐户。与 handleAuthorizationAppleIDButtonPress() 类似,授权控制器会设置其展示内容提供器,并委托给 LoginViewController 对象。

func performExistingAccountSetupFlows() {
    // Prepare requests for both Apple ID and password providers.
    let requests = [ASAuthorizationAppleIDProvider().createRequest(),                    ASAuthorizationPasswordProvider().createRequest()]
    
    // Create an authorization controller with the given requests.
    let authorizationController = ASAuthorizationController(authorizationRequests: requests)
    authorizationController.delegate = self
    authorizationController.presentationContextProvider = self
    authorizationController.performRequests()
}

authorizationController(controller:didCompleteWithAuthorization:) 委托函数会检查凭证是 Apple ID (ASAuthorizationAppleIDCredential(英文)) 还是密码凭证 (ASPasswordCredential(英文))。如果是密码凭证,系统会显示一条提醒,允许用户使用现有帐户进行认证。

启动时检查用户凭证

示例 app 仅在必要时显示“通过 Apple 登录”用户界面。App 委托会在 app 启动后立即通过appDelegate.application(_:didFinishLaunchingWithOptions:) 函数检查已存储用户凭证的状态。

getCredentialState(forUserID:completion:)(英文) 函数会检索钥匙串中存储的用户标识符的状态。如果用户为 app 授权了 (例如,用户在设备上使用 Apple ID 登录了 app),那么 app 会继续执行。如果用户撤销了对 app 的授权,或者 app 找不到用户的凭证状态,app 会通过调用 showLoginViewController() 函数来显示登录表单。

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    let appleIDProvider = ASAuthorizationAppleIDProvider()
    appleIDProvider.getCredentialState(forUserID: KeychainItem.currentUserIdentifier) { (credentialState, error) in
        switch credentialState {
        case .authorized:
            break // The Apple ID credential is valid.
        case .revoked, .notFound:
            // The Apple ID credential is either revoked or was not found, so show the sign-in UI.
            DispatchQueue.main.async {
                self.window?.rootViewController?.showLoginViewController()
            }
        default:
            break
        }
    }
    return true
}

PS:

用户每次登录都可以获取用户的userID

只有在用户首次登录的时候才可以根据用户自己的选择授权获取用户的信息

可以获取用户的姓或者名(用户必须给予至少其中一个)以及邮箱(用户可选择隐藏)

在手机->设置->点击头像进入密码与安全性->使用Apple ID的app->选择应用->停止使用Apple ID 就可以使应用的Apple ID登录更新为首次登录