This is the sixth day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

preface

Recently, an old company project, to do third-party login, said to make the user login experience more friendly.

In my opinion, it is stupid for an App to do a certain stage and then consider introducing a third party login.

At present, the App already uses the mobile phone number as the login identifier, and in the background database, the USER’s UID has been bound to the mobile phone number. Basically, it can be considered that the mobile phone number has been used as the primary key.

At the present stage, the third party login is added. After the user successfully logs in for the first time, the user still needs to associate with the mobile phone number, which makes me feel like taking off my pants and farting.

Everyone to this how to see, can discuss together, this is just my more radical point of view, because I have to write function, can’t be happy in the nuggets above touch fish.

Of course, when it comes to joining the third-party login, Apple login must also be added according to Apple’s regulations, otherwise it cannot be posted.

Therefore, I have this article, a summary of the development of Apple login. Although they are knowledge points from two years ago, I am still old and new. Combined with the business situation of App in the development process, I have made a summary and thought, and I can take notes by myself.

Pay attention to the comments in the code block!!

Apple login

Enable the function

To be able to use this function in our own App, we need to enable this function in the App:

Then enable this feature in the Developer developer Identifiers→ BoundleID of the corresponding App:

Apple official Demo learning

I studied apple’s official Demo code very carefully when writing this feature.

There are many times when we don’t know what to do with a new feature, and checking and learning the official code is a great example.

Apple logon logic processing, this step is very simple, is a service, set up a proxy callback, request to go!

@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()

}
Copy the code

Proxy callback, here we pay attention to my code inside the comment, more important oh:

extension LoginViewController: ASAuthorizationControllerDelegate { /// - Tag: did_complete_authorization func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {switch authorization.credential {/// Note that biometric, fingerprint or faceId is preferred for the first Apple login. It will prompt you to use Apple login password, if the password is passed, will go to this case let appleIDCredential as ASAuthorizationAppleIDCredential, once biological recognition for the first time, And biometric didn't pass, and still use the password to login, Apple will go this case let appleIDCredential as ASAuthorizationAppleIDCredential: // system generated user, Let userIdentifier = appleidCredential. user // Save the user name to the Keychain self.saveUserInkeychain (userIdentifier) // These two are available and only available when you log in with Apple for the first time, Can't take these data after the second let fullName = appleIDCredential. FullName let email = appleIDCredential. Email / / / the JWT string is very important, need to App background, App background call Apple background, to verify the validity of the account if the let identityToken = appleIDCredential. IdentityToken {let JWT = String (data: identityToken, encoding: .utf8) print(JWT)} /// For the device that does not have biometric function but uses Apple login, it seems that it is not the iPhone\iPad series product, old Mac\TV\Watch case let passwordCredential as ASPasswordCredential: // Sign in using an existing iCloud Keychain credential. let username = passwordCredential.user let password = passwordCredential.password default: break } } }Copy the code

In general, there is important information in this Apple login success callback, in which we need to do the following:

  • Get appleIDCredential. User

  • Store appleidCredential. user in the Keychain. Why, as we’ll see later

  • Will appleIDCredential identityToken to JWT string, easy to pass to App background, and then the App background with the Apple background interaction, do check (although we have no relationship between the project back end to interact with the background of mobile end, but a bit of no harm)

Apple login authorization cancels with the App at this time what needs to be done

Here we break it down into two cases:

  • The App is hung in the background through Apple login, and then the system setting page is used to delete the authorization of Apple login in the App. At this time, the App needs to do the corresponding operation, which can be learned by listening the notification:

    extension AppDelegate { func observeAppleSignInState() { NotificationCenter.default.addObserver(self, selector: #selector(handleSignInWithAppleStateChanged(notification:)), name: ASAuthorizationAppleIDProvider.credentialRevokedNotification, object: nil) } @objc func handleSignInWithAppleStateChanged(notification: NSNotification) {print(notification.userInfo) // delete the appleidcredential. user generated by saving the current Apple account in the Keychain}}Copy the code
  • The App was killed, and then we went to the system setting page and deleted the authorization of Apple login in the App. Next time we click into the App, we can handle some business through the callback provided by the system. Meanwhile, we need to pay attention to: Here we obtain the state of the previously saved userIdentifier from the Keychain:

    extension AppDelegate { func getCredentialState() { let appleIDProvider = ASAuthorizationAppleIDProvider() /// Note into the reference here is KeychainItem currentUserIdentifier, more detailed you can watch the official Demo, notice here is the study of logic rather than code implementation appleIDProvider. GetCredentialState (forUserID: KeychainItem.currentUserIdentifier) { (credentialState, error) in switch credentialState { case .authorized: // The Apple ID credential is valid. break case .revoked, .notFound: // The Apple ID credential is either revoked or was not found, // Delete the appleidcredential. user generated by saving the current Apple account in Keychain // If the App has automatic login, it should be blocked. Break default: break}}}}Copy the code
  • The above two methods are added to the func application (_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        getCredentialState()
        observeAppleSignInState()
        return true
    }
    Copy the code

thinking

Here’s a business situation you need to be aware of:

App first uses Apple login successfully, then logs out, and then uses QQ login successfully, then logs out, and then cancels Apple login authorization in this App and starts the App again. According to the logic written above, it will inevitably go to the logic dealing with the change of Apple login status.

So here’s what we need to think about:

  • When a variety of third-party login services are mixed, the cancellation of authorization for Apple login is a place we need to pay attention to and consider. In this App transformation, I suffered losses in the business situation of my App, so we should also pay attention to the usefulness of saving the last successful third-party login.

  • Appleidcredential. user is stored in the Keychain instead of the App sandbox.

  • Why do I delete appleidCredential. user saved in Keychain when I know Apple login authorization is cancelled?

Reference documentation

Implementing User Authentication with Sign in with Apple

jwt.io

Sign In With Apple

IOS 13 Apple account login is related to background authentication

AppleID authorized login App (Java backend authentication)

conclusion

In fact, overall, Apple login is not particularly complex, it is in fact and you use other third party login, such as QQ, wechat are a principle.

Change the Apple background into QQ background or wechat background in this flow chart, the idea is the same:

  • The App first obtains the login identifier through QQ SDK/ wechat SDK

  • The App sends the login identifier back to the App background

  • App background will then login identifier to QQ background/wechat background for verification

  • QQ background/wechat background callback to App background, App background back to App

Here I combine the business situation, leaving thoughts and my understanding of third party logins, which might be a little enlightening if you also have integrated Apple logins.