共用方式為


教學課程:使用原生驗證在iOS/macOS應用程式中新增登入和註銷

適用於白色圓圈,帶有灰色 X 符號。 Workforce 租戶 綠色圓圈,帶有白色複選標記符號。 外部租戶(深入瞭解

本教學課程示範如何使用原生驗證,在iOS/macOS應用程式中使用電子郵件單次密碼或使用者名稱和密碼來登入和註銷使用者。

在本教學課程中,您將瞭解如何:

  • 使用電子郵件一次性密碼或使用者名稱(電子郵件)和密碼登入使用者。
  • 註銷使用者。
  • 處理登入錯誤

先決條件

登入使用者

若要使用 電子郵件單次密碼 流程登入使用者,請擷取電子郵件,並傳送包含一次性密碼的電子郵件,讓使用者驗證其電子郵件。 當使用者輸入有效的單次密碼時,應用程式會將其登入。

若要使用 電子郵件搭配密碼 流程登入使用者,請擷取電子郵件和密碼。 如果使用者名稱和密碼有效,應用程式會登入使用者。

若要登入使用者,您需要:

  1. 建立使用者介面 (UI) 以:

    • 從使用者收集電子郵件。 將驗證新增至您的輸入,以確保使用者輸入有效的電子郵件位址。
    • 如果您使用使用者名稱(電子郵件)和密碼登入,請收集密碼。
    • 如果您使用電子郵件一次性密碼登入,請從使用者收集電子郵件一次性密碼。
    • 新增按鈕,讓使用者使用電子郵件一次性密碼登入時,重新傳送一次性密碼。
  2. 在您的UI中,新增按鈕,其 select 事件會啟動登入,如下列代碼段所示:

        @IBAction func signInPressed(_: Any) {
        guard let email = emailTextField.text else {
            resultTextView.text = "email not set"
            return
        }
    
        let parameters = MSALNativeAuthSignInParameters(username: email)
        nativeAuth.signIn(parameters: parameters, delegate: self)
    }
    

    若要使用 電子郵件單次密碼 流程登入使用者,我們使用下列代碼段:

    nativeAuth.signIn(parameters: parameters, delegate: self)
    

    signIn(parameters:delegate) 方法必須實作 SignInStartDelegate 通訊協定,此方法會在傳遞的委派物件上呼叫某個方法以進行異步回應。 我們會傳遞 MSALNativeAuthSignInParameters 的實例,其中包含使用者在電子郵件提交表單中提供的電子郵件位址,並將 self 作為委派進行傳遞。

    若要使用 Email 搭配密碼 流程登入使用者,我們會使用下列代碼段:

    let parameters = MSALNativeAuthSignInParameters(username: email)
    parameters.password = password
    nativeAuth.signIn(parameters: parameters, delegate: self)
    

    signIn(parameters:delegate) 方法中,您會傳遞 MSALNativeAuthSignInParameters 實例,其中包含使用者提供的電子郵件位址及其密碼,以及符合 SignInStartDelegate 通訊協定的委派物件。 在這個範例中,我們會傳遞 self

  3. 若要在使用 電子郵件單次密碼 流程時實作 SignInStartDelegate 通訊協定,請使用下列代碼段:

    extension ViewController: SignInStartDelegate {
        func onSignInStartError(error: MSAL.SignInStartError) {
            resultTextView.text = "Error signing in: \(error.errorDescription ?? "no description")"
        }
    
        func onSignInCodeRequired(
            newState: MSAL.SignInCodeRequiredState,
            sentTo: String,
            channelTargetType: MSAL.MSALNativeAuthChannelType,
            codeLength: Int
        ) {
            resultTextView.text = "Verification code sent to \(sentTo)"
        }
    }
    

    signIn(parameters:delegate) 會導致呼叫委派方法。 在最常見的案例中,會呼叫 onSignInCodeRequired(newState:sentTo:channelTargetType:codeLength),指出已傳送程式代碼來驗證用戶的電子郵件位址。 除了有關程式碼傳送目的地的一些詳細信息及其位數外,該委派方法還具有一個類型為 SignInCodeRequiredStatenewState 參數,使我們可以存取以下兩個新方法:

    • submitCode(code:delegate)
    • resendCode(delegate)

    使用 submitCode(code:delegate) 提交使用者以單次密碼形式提供的一次性密碼,請使用下列代碼段:

    newState.submitCode(code: userSuppliedCode, delegate: self)
    

    submitCode(code:delegate) 接受一次性密碼和委派參數。 提交程式代碼之後,您必須實作 SignInVerifyCodeDelegate 通訊協議來驗證單次密碼。

    若要將 SignInVerifyCodeDelegate 通訊協定實作為類別的延伸模組,請使用下列代碼段:

    extension ViewController: SignInVerifyCodeDelegate {
        func onSignInVerifyCodeError(error: MSAL.VerifyCodeError, newState: MSAL.SignInCodeRequiredState?) {
            resultTextView.text = "Error verifying code: \(error.errorDescription ?? "no description")"
        }
    
        func onSignInCompleted(result: MSALNativeAuthUserAccountResult) {
            resultTextView.text = "Signed in successfully."
            let parameters = MSALNativeAuthGetAccessTokenParameters()
            result.getAccessToken(parameters: parameters, delegate: self)
        }
    }
    

    在最常見的案例中,我們會收到呼叫 onSignInCompleted(result),指出使用者已登入。 結果可用來擷取 access token

    getAccessToken(parameters:delegate) 接受 MSALNativeAuthGetAccessTokenParameters 實例和委派參數,我們必須在 CredentialsDelegate 通訊協定中實作必要的方法。

    在最常見的案例中,我們收到呼叫 onAccessTokenRetrieveCompleted(result),指出使用者已取得 access token

    extension ViewController: CredentialsDelegate {
        func onAccessTokenRetrieveError(error: MSAL.RetrieveAccessTokenError) {
            resultTextView.text = "Error retrieving access token"
        }
    
        func onAccessTokenRetrieveCompleted(result: MSALNativeAuthTokenResult) {
            resultTextView.text = "Signed in. Access Token: \(result.accessToken)"
        }
    }
    
    
  4. 若要在搭配密碼 流程使用 Email 時實作 SignInStartDelegate 通訊協定,請使用下列代碼段:

    extension ViewController: SignInStartDelegate {
        func onSignInStartError(error: MSAL.SignInStartError) {
            resultTextView.text = "Error signing in: \(error.errorDescription ?? "no description")"
        }
    
        func onSignInCompleted(result: MSAL.MSALNativeAuthUserAccountResult) {
            // User successfully signed in
        }
    }
    

    在最常見的案例中,我們會收到呼叫 onSignInCompleted(result),指出使用者已登入。 結果可用來擷取 access token

    getAccessToken(parameters:delegate) 接受 MSALNativeAuthGetAccessTokenParameters 實例和委派參數,我們必須在 CredentialsDelegate 通訊協定中實作必要的方法。

    在最常見的情況下,我們接到一個onAccessTokenRetrieveCompleted(result)的呼叫,表明使用者已取得access token

    extension ViewController: CredentialsDelegate {
        func onAccessTokenRetrieveError(error: MSAL.RetrieveAccessTokenError) {
            resultTextView.text = "Error retrieving access token"
        }
    
        func onAccessTokenRetrieveCompleted(result: MSALNativeAuthTokenResult) {
            resultTextView.text = "Signed in. Access Token: \(result.accessToken)"
        }
    }
    
    

處理登入錯誤

登入期間,並非每個動作都成功。 例如,使用者可能會嘗試使用不存在的電子郵件位址登入,或提交無效的程序代碼。

  1. 若要處理 signIn(parameters:delegate) 方法中的錯誤,請使用下列代碼段:

    func onSignInStartError(error: MSAL.SignInStartError) {
        if error.isUserNotFound || error.isInvalidUsername {
            resultTextView.text = "Invalid username"
        } else {
            resultTextView.text = "Error signing in: \(error.errorDescription ?? "no description")"
        }
    }
    
  2. 若要處理 submitCode() 方法中的錯誤,請使用下列代碼段:

    func onSignInVerifyCodeError(error: MSAL.VerifyCodeError, newState: MSAL.SignInCodeRequiredState?) {
        if error.isInvalidCode {
            // Inform the user that the submitted code was incorrect and ask for a new code to be supplied
            let userSuppliedCode = retrieveNewCode()
            newState?.submitCode(code: userSuppliedCode, delegate: self)
        } else {
            resultTextView.text = "Error verifying code: \(error.errorDescription ?? "no description")"
        }
    }
    

    如果使用者輸入不正確的電子郵件驗證碼,錯誤處理程式會包含一個名為 SignInCodeRequiredState 的參考,用於提交更新的驗證碼。 在先前的 SignInVerifyCodeDelegate 通訊協定實作中,我們只會在處理 onSignInVerifyCodeError(error:newState) 委派函式時顯示錯誤。

讀取 ID 令牌聲明

一旦您的應用程式取得 ID 令牌,您就可以擷取目前帳戶的相關宣告。 若要這樣做,請使用下列代碼段:

func onSignInCompleted(result: MSAL.MSALNativeAuthUserAccountResult) {
   let claims = result.account.accountClaims
   let preferredUsername = claims?["preferred_username"] as? String
}

您用來存取宣告值的鍵,是您在將使用者屬性新增為令牌宣告時所指定的名稱。

瞭解如何將內建和自定義屬性新增為令牌宣告,將用戶屬性新增至令牌宣告 一文。

註銷使用者

若要註銷使用者,請使用您在 onSignInCompleted 回呼中收到的 MSALNativeAuthUserAccountResult 參考,或使用 getNativeAuthUserAccount() 從快取取得任何登入的帳戶,並將參考儲存在 accountResult 成員變數中。

  1. 請按照這裡的說明設定您的項目金鑰鏈群組

  2. 將新的成員變數新增至您的 ViewController 類別:var accountResult: MSALNativeAuthUserAccountResult?

  3. 成功初始化 nativeAuth 之後,加入此行以更新 viewDidLoad 來檢索任何快取的帳戶:accountResult = nativeAuth.getNativeAuthUserAccount()

  4. 更新 signInCompleted 處理程式以儲存帳戶結果:

    func onSignInCompleted(result: MSALNativeAuthUserAccountResult) {
        resultTextView.text = "Signed in successfully"
    
        accountResult = result
    }
    
  5. 新增 [註銷] 按鈕,並使用下列程式代碼來註銷使用者:

    @IBAction func signOutPressed(_: Any) {
        guard let accountResult = accountResult else {
            print("Not currently signed in")
            return
        }
    
        accountResult.signOut()
    
        self.accountResult = nil
    
        resultTextView.text = "Signed out"
    }
    

您已成功完成所有必要步驟,以註銷應用程式上的使用者。 建置並執行您的應用程式。 如果一切順利,您應該能夠選取 [註銷] 按鈕以成功註銷。

設定自定義宣告提供者

如果您想將來自外部系統的宣告新增到發行給應用程式的權杖中,請使用 自訂宣告提供者。 自定義宣告提供者是由自定義驗證延伸模組所組成,可呼叫外部 REST API 從外部系統擷取宣告。

請遵循 設定自定義宣告提供者 中的步驟,將外部系統的宣告新增至安全性令牌。