Sign in with Apple 從登陸到服務器驗證 看我這個鏈接。
WWDC2019大會上,蘋果將支持使用AppleID
進行登錄。這篇文件記錄并介紹下Sing in with Apple這篇視頻中所介紹的內容,即使用AppleID
登錄。
AppleID
登錄的一些特性
- 簡化賬號的創建和登錄流程,無縫跨設備使用
- 開發者可以獲取到已驗證過的郵箱作為登錄賬號或者與用戶進行通信(注:用戶可以選擇隱藏真實郵箱,并使用蘋果提供的虛擬郵箱進行授權)
- 尊重用戶隱私,開發者只可獲取郵箱及姓名
- 反欺詐,使用機器學習等技術和其他信息,幫助開發者判斷一個賬號是否真實
- 跨平臺
image.png
登錄流程圖:
image.png
代碼操作
- 在項目中找到如圖所示位置,點擊并添加
Sign in with Apple
這里需要注意的是,你的對應證書里面也要添加對應的權限
image.png
image.png
- 導入框架
import AuthenticationServices
創建登錄按鈕(蘋果框架中提供了一個現成的)
// Add “Sign In with Apple” button to your login view
func setUpProviderLoginView() {
let button = ASAuthorizationAppleIDButton()
button.addTarget(self, action:#selector(handleAuthorizationAppleIDButtonPress),
for: .touchUpInside)
self.loginProviderStackView.addArrangedSubview(button)
}
// Configure request, setup delegates and perform authorization request
@objc func handleAuthorizationButtonPress() {
let request = ASAuthorizationAppleIDProvider().createRequest()
request.requestedScopes = [.fullName, .email]
let controller = ASAuthorizationController(authorizationRequests: [request])
controller.delegate = self
controller.presentationContextProvider = self
controller.performRequests()
}
ASAuthorization.Scope
是一個枚舉,可以獲取到用戶的name
及email
extension ASAuthorization.Scope {
@available(iOS 13.0, *)
public static let fullName: ASAuthorization.Scope
@available(iOS 13.0, *)
public static let email: ASAuthorization.Scope
}
登錄方法中我們需要遵循兩個協議:ASAuthorizationControllerDelegate
和ASAuthorizationControllerPresentationContextProviding
@available(iOS 13.0, *)
public protocol ASAuthorizationControllerDelegate : NSObjectProtocol {
optional func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization)
optional func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error)
}
@available(iOS 13.0, *)
public protocol ASAuthorizationControllerPresentationContextProviding : NSObjectProtocol {
/** @abstract Return a view anchor that is most appropriate for athorization UI to be presented over. This view will be used as a hint if a credential provider requires user interaction.
*/
func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor
}
其中presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor
方法我們需要返回一個window
注: public typealias ASPresentationAnchor = UIWindow
func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
return self.view.window!
}
這時候你點擊按鈕應該可以看到如下界面:
image.png
- 登錄回調
ASAuthorizationControllerDelegate
這個協議中的兩個方法即為登錄成功及失敗的回調
func authorizationController(controller _: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
switch authorization.credential {
case let appleIdCredential as ASAuthorizationAppleIDCredential:
let userIdentifier = appleIdCredential.user
let identityToken = appleIdCredential.identityToken
let authCode = appleIdCredential.authorizationCode
let realUserStatus = appleIdCredential.realUserStatus
default:
break
}
}
func authorizationController(_: ASAuthorizationController, didCompleteWithError error: Error) {
// Handle error
}
如果用戶之前已經登陸過,那么我們可以提醒用戶輸入密碼直接登錄之前的賬號,代碼如下
func performExistingAccountSetupFlows() {
let requests = [ASAuthorizationAppleIDProvider().createRequest(),
ASAuthorizationPasswordProvider().createRequest()]
let controller = ASAuthorizationController(authorizationRequests: requests)
controller.delegate = self
controller.presentationContextProvider = self
controller.performRequests()
}
然后修改回調方法,在上面的switch-case
語句中添加一個case
case let passwordCredential as ASPasswordCredential:
// Sign in using an existing iCloud Keychain credential.
break
- 檢查用戶登錄狀態
這個操作我們可以放到AppDelegate
中的app did finish launching
中,因為蘋果告訴我們the api is very fast
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
fallthrough
case .notFound:
// Credential not found, show login UI
default: break
}
}
- 監聽用戶是否取消對app的登錄授權
// Register for revocation notification
let center = NotificationCenter.default
let name = ASAuthorizationAppleIDProvider.credentialRevokedNotification
let observer = center.addObserver(forName: name, object: nil, queue: nil) { (Notification) in
// Sign the user out, optionally guide them to sign in again
}