【iOS】苹果登录Sign in with Apple

时间:2024-03-04 19:57:43

  在iOS13中,如果苹果开发者提供任何其他第三方登录,就必须提供“苹果登录”选项。也就是说,如果软件要求“微信登录”或是“QQ登录”时,必须同时提供“苹果登录”的选项给用户自行选择。根据苹果公司最新公布的指南,要求开发者在苹果终端的应用程序登录界面上,将“苹果登录”选项列在任何其他第三方登录的选项之上。

  注:以下内容源于官方文档翻译Sign in with Apple

  1、添加登录按钮

  在示例应用程序中,LoginViewController在其视图层次结构中显示一个登录表单和一个使用Apple按钮(ASAuthorizationAppleIDButton)登录的表单。视图控制器还将自己添加为按钮的目标,并传递一个操作,当按钮接收到修饰事件时调用。
func setupProviderLoginView() {
    let authorizationButton = ASAuthorizationAppleIDButton()
    authorizationButton.addTarget(self, action: #selector(handleAuthorizationAppleIDButtonPress), for: .touchUpInside)
    self.loginProviderStackView.addArrangedSubview(authorizationButton)
}

  提示:当你在故事板中添加用苹果按钮登录时,你还必须在Xcode的身份检查器中将控件的类值设置为ASAuthorizationAppleIDButton。

  2、请求Apple ID授权

  当用户点击Apple按钮登录时,视图控制器调用handleAuthorizationAppleIDButtonPress()函数,该函数通过对用户的全名和电子邮件地址执行授权请求来启动身份验证流程。然后,系统检查用户是否用设备上的Apple ID登录。如果用户没有在系统级登录,应用程序会显示一个警告,指示用户在设置中使用他们的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()
}

  提示:用户在使用“登录与苹果”(Sign in with Apple)时,必须启用双重身份验证,这样才能安全访问该账户。

  授权控制器调用presentationAnchor(for:)函数来从应用程序获取窗口,在窗口中,它会以模态表单的形式向用户显示带有苹果内容的登录。

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

  如果用户使用Apple ID在系统级登录,则会出现描述使用Apple功能登录的工作表,然后是另一个工作表,允许用户编辑其帐户中的信息。用户可以编辑他们的第一个和最后一个名称,选择另一个电子邮件地址作为他们的联系信息,并从应用程序隐藏他们的电子邮件地址。如果用户选择隐瞒自己的电子邮件地址从应用程序,苹果会生成一个代理邮箱地址转发邮件到用户的私人电子邮件地址。最后,用户输入Apple ID的密码,然后单击Continue创建帐户。

  3、Handle User Credentials

  如果验证成功,授权控制器调用authorizationController(controller:didCompleteWithAuthorization:)委托函数,应用程序使用该函数在密钥链中存储用户数据。

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.
}

  一旦系统验证了用户,应用程序就会显示ResultViewController,它会显示框架请求的用户信息,包括用户提供的全名和电子邮件地址。视图控制器还显示一个Sign Out按钮,并将用户数据存储在密钥链中。当用户点击Sign Out按钮时,应用程序从视图控制器和密钥链中删除用户信息,并将LoginViewController呈现给用户。

  4、要求现有的凭证

  performexistingaccountsetupflows()函数的作用是:通过请求苹果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()
}