Sign in with Apple 從登陸到服務(wù)器驗(yàn)證 看我這個(gè)鏈接蔓涧。
WWDC2019大會上件已,蘋果將支持使用AppleID
進(jìn)行登錄。這篇文件記錄并介紹下Sing in with Apple這篇視頻中所介紹的內(nèi)容元暴,即使用AppleID
登錄篷扩。
AppleID
登錄的一些特性
- 簡化賬號的創(chuàng)建和登錄流程,無縫跨設(shè)備使用
- 開發(fā)者可以獲取到已驗(yàn)證過的郵箱作為登錄賬號或者與用戶進(jìn)行通信(注:用戶可以選擇隱藏真實(shí)郵箱茉盏,并使用蘋果提供的虛擬郵箱進(jìn)行授權(quán))
- 尊重用戶隱私鉴未,開發(fā)者只可獲取郵箱及姓名
- 反欺詐,使用機(jī)器學(xué)習(xí)等技術(shù)和其他信息鸠姨,幫助開發(fā)者判斷一個(gè)賬號是否真實(shí)
- 跨平臺
image.png
登錄流程圖:
image.png
代碼操作
- 在項(xiàng)目中找到如圖所示位置铜秆,點(diǎn)擊并添加
Sign in with Apple
這里需要注意的是,你的對應(yīng)證書里面也要添加對應(yīng)的權(quán)限
image.png
image.png
- 導(dǎo)入框架
import AuthenticationServices
創(chuàng)建登錄按鈕(蘋果框架中提供了一個(gè)現(xiàn)成的)
// 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
是一個(gè)枚舉讶迁,可以獲取到用戶的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
}
登錄方法中我們需要遵循兩個(gè)協(xié)議: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
方法我們需要返回一個(gè)window
注: public typealias ASPresentationAnchor = UIWindow
func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
return self.view.window!
}
這時(shí)候你點(diǎn)擊按鈕應(yīng)該可以看到如下界面:
image.png
- 登錄回調(diào)
ASAuthorizationControllerDelegate
這個(gè)協(xié)議中的兩個(gè)方法即為登錄成功及失敗的回調(diào)
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
}
如果用戶之前已經(jīng)登陸過连茧,那么我們可以提醒用戶輸入密碼直接登錄之前的賬號,代碼如下
func performExistingAccountSetupFlows() {
let requests = [ASAuthorizationAppleIDProvider().createRequest(),
ASAuthorizationPasswordProvider().createRequest()]
let controller = ASAuthorizationController(authorizationRequests: requests)
controller.delegate = self
controller.presentationContextProvider = self
controller.performRequests()
}
然后修改回調(diào)方法巍糯,在上面的switch-case
語句中添加一個(gè)case
case let passwordCredential as ASPasswordCredential:
// Sign in using an existing iCloud Keychain credential.
break
- 檢查用戶登錄狀態(tài)
這個(gè)操作我們可以放到AppDelegate
中的app did finish launching
中啸驯,因?yàn)樘O果告訴我們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
}
}
- 監(jiān)聽用戶是否取消對app的登錄授權(quán)
// 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
}