Esercitazione: reimpostazione autonoma della password nell'app iOS/macOS

Si applica a: cerchio verde con un segno di spunta bianco che indica che il contenuto seguente si applica ai tenant esterni. Tenant esterni (altre informazioni)

Questa esercitazione illustra come offrire agli utenti la possibilità di modificare o reimpostare la password, senza coinvolgimento dell'amministratore o dell'help desk.

In questa esercitazione, farai:

  • Aggiungi la reimpostazione della password self-service.
  • Gestire gli errori.

Prerequisiti

Immettere una nuova password

Per reimpostare la password di un utente esistente, è necessario convalidare l'indirizzo di posta elettronica usando un passcode monouso (OTP).

  1. Per convalidare il messaggio di posta elettronica, viene chiamato il metodo resetPassword(parameters:delegate) dall'istanza dell'SDK usando il frammento di codice seguente:

    let parameters = MSALNativeAuthResetPasswordParameters(username: email)
    nativeAuth.resetPassword(parameters: parameters, delegate: self)
    
  2. Per implementare il protocollo ResetPasswordStartDelegate come estensione per la classe, usare il frammento di codice seguente:

    extension ViewController: ResetPasswordStartDelegate {
        func onResetPasswordCodeRequired(
            newState: MSAL.ResetPasswordCodeRequiredState,
            sentTo: String,
            channelTargetType: MSALNativeAuthChannelType,
            codeLength: Int
        ) {
            resultTextView.text = "Verification code sent to \(sentTo)"
        }
    
        func onResetPasswordStartError(error: MSAL.ResetPasswordStartError) {
            resultTextView.text = "Error verifying code: \(error.errorDescription ?? "no description")"
        }
    }
    

    La chiamata a resetPassword(parameters:delegate) comporta una chiamata ai metodi delegati onResetPasswordCodeRequired() o onResetPasswordStartError().

    Nello scenario onResetPasswordCodeRequired(newState:sentTo:channelTargetType:codeLength) più comune verrà chiamato per indicare che è stato inviato un codice per verificare l'indirizzo di posta elettronica dell'utente. Oltre ad alcuni dettagli sulla posizione in cui è stato inviato il codice e sul numero di cifre che contiene, questo metodo delegato ha anche un parametro newState di tipo ResetPasswordCodeRequiredState, che consente di accedere a due nuovi metodi:

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

    Per inviare il codice fornito dall'utente, usare:

    newState.submitCode(code: userSuppliedCode, delegate: self)
    
  3. Per verificare il codice inviato, iniziare implementando il protocollo ResetPasswordVerifyCodeDelegate come estensione alla classe usando il frammento di codice seguente:

    extension ViewController: ResetPasswordVerifyCodeDelegate {
    
        func onResetPasswordVerifyCodeError(
            error: MSAL.VerifyCodeError,
            newState: MSAL.ResetPasswordCodeRequiredState?
        ) {
            resultTextView.text = "Error verifying code: \(error.errorDescription ?? "no description")"
        }
    
        func onPasswordRequired(newState: MSAL.ResetPasswordRequiredState) {
            // use newState instance to submit the new password
        }
    }
    

    Nello scenario più comune viene ricevuta una chiamata a onPasswordRequired(newState) che indica che è possibile fornire la nuova password usando l'istanza di newState.

    newState.submitPassword(password: newPassword, delegate: self)
    
  4. Per implementare il protocollo ResetPasswordRequiredDelegate come estensione per la classe, usare il frammento di codice seguente:

    extension ViewController: ResetPasswordRequiredDelegate {
    
        func onResetPasswordRequiredError(
            error: MSAL.PasswordRequiredError,
            newState: MSAL.ResetPasswordRequiredState?
        ) {
            resultTextView.text = "Error submitting new password: \(error.errorDescription ?? "no description")"
        }
    
        func onResetPasswordCompleted(newState: SignInAfterResetPasswordState) {
            resultTextView.text = "Password reset completed"
        }
    }
    

    Nello scenario più comune viene ricevuta una chiamata a onResetPasswordCompleted(newState) che indica che il flusso di reimpostazione della password è stato completato.

Gestire gli errori

Nell'implementazione precedente del protocollo ResetPasswordStartDelegate l'errore veniva visualizzato durante la gestione della funzione di delegato onResetPasswordStartError(error).

È possibile migliorare l'esperienza utente gestendo il tipo di errore specifico come indicato di seguito:

func onResetPasswordStartError(error: MSAL.ResetPasswordStartError) {
    if error.isInvalidUsername {
        resultTextView.text = "Invalid username"
    } else if error.isUserNotFound {
        resultTextView.text = "User not found"
    } else if error.isUserDoesNotHavePassword {
        resultTextView.text = "User is not registered with a password"
    } else {
        resultTextView.text = "Error during reset password flow in: \(error.errorDescription ?? "no description")"
    }
}

Gestire gli errori tramite stati

Alcuni errori includono un riferimento a un nuovo stato. Ad esempio, se l'utente immette un codice di verifica di posta elettronica non corretto, il gestore degli errori include un riferimento a un ResetPasswordCodeRequiredState che può essere usato per inviare un nuovo codice di verifica.

Nell'implementazione precedente del protocollo ResetPasswordVerifyCodeDelegate è stato semplicemente visualizzato l'errore quando è stata gestita la funzione delegato onResetPasswordError(error:newState).

È possibile migliorare l'esperienza utente chiedendo all'utente di immettere il codice corretto e inviarlo nuovamente come indicato di seguito:

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

Un altro esempio in cui il gestore degli errori include un riferimento a un nuovo stato è quando l'utente immette una password non valida. In questo caso, il gestore degli errori include un riferimento a un ResetPasswordRequiredState che può essere usato per inviare una nuova password. Ecco un esempio:

func onResetPasswordRequiredError(
    error: MSAL.PasswordRequiredError,
    newState: MSAL.ResetPasswordRequiredState?
) {
    if error.isInvalidPassword {
        // Inform the user that the submitted password was invalid and ask for a new password to be supplied.
        let newPassword = retrieveNewPassword()
        newState?.submitPassword(password: newPassword, delegate: self)
    } else {
        resultTextView.text = "Error submitting password: \(error.errorDescription ?? "no description")"
    }
}

Accedere dopo la reimpostazione della password

L'SDK offre agli sviluppatori la possibilità di accedere a un utente dopo la reimpostazione della password senza dover specificare il nome utente o di verificare l'indirizzo di posta elettronica tramite un passcode monouso.

Per accedere a un utente dopo la reimpostazione della password, usare il metodo signIn(parameters:delegate) dal nuovo stato SignInAfterResetPasswordState restituito nella funzione onResetPasswordCompleted(newState):

extension ViewController: ResetPasswordRequiredDelegate {

    func onResetPasswordRequiredError(
        error: MSAL.PasswordRequiredError,
        newState: MSAL.ResetPasswordRequiredState?
    ) {
        resultTextView.text = "Error submitting new password: \(error.errorDescription ?? "no description")"
    }

    func onResetPasswordCompleted() {
        resultTextView.text = "Password reset completed"
        let parameters = MSALNativeAuthSignInAfterResetPasswordParameters()
        newState.signIn(parameters: parameters, delegate: self)
    }
}

Il signIn(parameters:delegate) accetta un parametro delegato ed è necessario implementare i metodi necessari nel protocollo di SignInAfterResetPasswordDelegate.

Nello scenario più comune viene ricevuta una chiamata a onSignInCompleted(result) che indica che l'utente ha eseguito l'accesso. Il risultato può essere usato per recuperare il access token.

extension ViewController: SignInAfterSignUpDelegate {
    func onSignInAfterSignUpError(error: SignInAfterSignUpError) {
        resultTextView.text = "Error signing in after password reset"
    }

    func onSignInCompleted(result: MSAL.MSALNativeAuthUserAccountResult) {
        // User successfully signed in
        let parameters = MSALNativeAuthGetAccessTokenParameters()
        result.getAccessToken(parameters: parameters, delegate: self)
    }
}

Il getAccessToken(parameters:delegate) accetta un parametro delegato ed è necessario implementare i metodi necessari nel protocollo di CredentialsDelegate.

Nello scenario più comune viene ricevuta una chiamata a onAccessTokenRetrieveCompleted(result) che indica che l'utente ha ottenuto un 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)"
    }
}

Passaggio successivo