Esercitazione: Aggiungere l'accesso e la disconnessione nell'app iOS/macOS usando l'autenticazione nativa
Si applica a: iOS (Swift) macOS (Swift)
Questa esercitazione illustra come consentire l'accesso e la disconnessione di un utente usando il passcode monouso tramite posta elettronica o username e password nell'app iOS/macOS utiizzando l'autenticazione nativa.
In questa esercitazione apprenderai a:
- Far accedere un utente usando il passcode monouso o il nome utente (e-mail) e la password.
- Disconnettere un utente.
- Gestire gli errori di accesso
Prerequisiti
- Esercitazione: Preparare l'app iOS per l'autenticazione nativa
- Se si vuole accedere usando posta elettronica con password, configurare il flusso utente per l'uso della posta elettronica con password nel momento in cui si crea il flusso utente di iscrizione e accesso.
Consentire l'accesso degli utenti
Per consentire l'accesso a un utente usando il flusso Passcode monouso tramite posta elettronica, acquisire l'indirizzo di posta elettronica e inviare un messaggio contenente un passcode monouso per permettere all'utente di verificare il proprio indirizzo. Quando l'utente immette un passcode monouso valido, l'app gli consente di accedere.
Per far accedere un utente usando il flusso di posta elettronica con password, acquisire il messaggio di posta elettronica e la password. Se il nome utente e la password sono validi, l'app consente all'utente di accedere.
Per far accedere un utente, è necessario:
Creare un'interfaccia utente (IU) per:
- Acquisire un’e-mail dall'utente. Aggiungere la convalida agli input per accertarsi che l'utente immetta un indirizzo di posta elettronica valido.
- Acquisire una password se si effettua l'iscrizione con il nome utente (e-mail) e la password.
- Raccogliere un passcode monouso tramite posta elettronica dall'utente se si accede con passcode monouso tramite posta elettronica.
- Aggiungere un pulsante per consentire all'utente di inviare nuovamente il passcode monouso se si accede con passcode monouso tramite posta elettronica.
Nell'interfaccia utente aggiungere un pulsante, la cui selezione avvia un accesso, come illustrato nel frammento di codice seguente:
@IBAction func signInPressed(_: Any) { guard let email = emailTextField.text else { resultTextView.text = "email not set" return } nativeAuth.signIn(username: email, delegate: self) }
Per far accedere un utente usando il flusso di passcode monouso tramite posta elettronica, viene usato il frammento di codice seguente:
nativeAuth.signIn(username: email, delegate: self)
Il metodo
signIn(username:delegate)
, che risponde in modo asincrono chiamando uno dei metodi sull'oggetto delegato passato, deve implementare il protocolloSignInStartDelegate
. Si passa l'indirizzo di posta elettronica che l'utente fornisce nel modulo di invio dell'indirizzo e si passaself
come delegato.Per far accedere un utente usando il flusso di posta elettronica con password, viene usato il frammento di codice seguente:
nativeAuth.signIn(username: email, password: password, delegate: self)
Nel metodo
signIn(username:password:delegate)
si passa l'indirizzo e-mail fornito dall'utente, la password e l'oggetto delegato conforme al protocolloSignInStartDelegate
. Per questo esempio, si passaself
.Per implementare il protocollo
SignInStartDelegate
quando si usa il flusso di passcode monouso tramite posta elettronica, usare il frammento di codice seguente: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)" } }
La chiamata a
signIn(username:delegate)
implica una chiamata a metodi delegati. Nello scenario più comune viene chiamatoonSignInCodeRequired(newState:sentTo:channelTargetType:codeLength)
per indicare che è stato inviato un codice per verificare l'indirizzo di posta elettronica dell'utente. Oltre ad alcuni dettagli sul destinatario del codice e sul numero di cifre che lo compongono, questo metodo delegato ha anche un parametronewState
di tipoSignInCodeRequiredState
, che consente di accedere ai due nuovi metodi seguenti:submitCode(code:delegate)
resendCode(delegate)
Usare
submitCode(code:delegate)
per inviare il passcode monouso fornito dall'utente nell'apposito modulo, usare il frammento di codice seguente:newState.submitCode(code: userSuppliedCode, delegate: self)
submitCode(code:delegate)
accetta il passcode monouso e il parametro delegato. Dopo aver inviato il codice, è necessario verificare il passcode monouso implementando il protocolloSignInVerifyCodeDelegate
.Per implementare il protocollo
SignInVerifyCodeDelegate
come estensione della propria classe, usare il frammento di codice seguente: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." result.getAccessToken(delegate: self) } }
Nello scenario più comune si riceve una chiamata a
onSignInCompleted(result)
, che indica che all'utente è stato consentito di accedere. Il risultato può essere usato per recuperare l'oggettoaccess token
.getAccessToken(delegate)
accetta un parametro delegato e occorre implementare i metodi richiesti nel protocolloCredentialsDelegate
.Nello scenario più comune viene ricevuta una chiamata a
onAccessTokenRetrieveCompleted(result)
che indica che l'utente ha ottenuto un oggettoaccess 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)" } }
Per implementare il protocollo
SignInStartDelegate
quando si usa il flusso di posta elettronica con password, usare il frammento di codice seguente: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 } }
Nello scenario più comune si riceve una chiamata a
onSignInCompleted(result)
, che indica che all'utente è stato consentito di accedere. Il risultato può essere usato per recuperare l'oggettoaccess token
.getAccessToken(delegate)
accetta un parametro delegato e occorre implementare i metodi richiesti nel protocolloCredentialsDelegate
.Nello scenario più comune viene ricevuta una chiamata a
onAccessTokenRetrieveCompleted(result)
che indica che l'utente ha ottenuto un oggettoaccess 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)" } }
Gestire gli errori di accesso
Durante l'accesso non tutte le azioni vengono completate correttamente. Ad esempio, l'utente potrebbe provare a eseguire l'accesso con un indirizzo di posta elettronica non esistente oppure inviare un codice non valido.
Per gestire gli errori nel metodo
signIn(username)
osignIn(username, password)
, usare il frammento di codice seguente:func onSignInStartError(error: MSAL.SignInStartError) { if error.isUserNotFound || error.isInvalidUsername { resultTextView.text = "Invalid username" } else { resultTextView.text = "Error signing in: \(error.errorDescription ?? "no description")" } }
Per gestire gli errori nel metodo
submitCode()
, usare il frammento di codice seguente: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")" } }
Se l'utente immette un codice di verifica di posta elettronica non corretto, il gestore degli errori include un riferimento a
SignInCodeRequiredState
che può essere usato per inviare un codice aggiornato. Nell'implementazione precedente del protocolloSignInVerifyCodeDelegate
l'errore veniva semplicemente visualizzato durante la gestione della funzione di delegatoonSignInVerifyCodeError(error:newState)
.
Leggere le attestazioni del token ID
Quando l'app ha acquisito un token ID, è possibile recuperare le attestazioni associate all'account corrente. Per completare questa operazione, usare il frammento di codice seguente:
func onSignInCompleted(result: MSAL.MSALNativeAuthUserAccountResult) {
let claims = result.account.accountClaims
let preferredUsername = claims?["preferred_username"] as? String
}
La chiave usata per accedere al valore dell'attestazione è il nome specificato quando si aggiunge l'attributo utente come attestazione token.
Informazioni su come aggiungere attributi predefiniti e personalizzati come attestazioni token nell'articolo Aggiungere attributi utente alle attestazioni token.
SignOutUser
Per disconnettere un utente, usare il riferimento a MSALNativeAuthUserAccountResult
ricevuto nel callback onSignInCompleted
oppure usare getNativeAuthUserAccount()
per ottenere qualsiasi account connesso dalla cache e archiviare un riferimento nella variabile membro accountResult
.
Configurare il gruppo di keychain per il progetto come descritto qui.
Aggiungere una nuova variabile membro alla classe
ViewController
:var accountResult: MSALNativeAuthUserAccountResult?
.Aggiornare
viewDidLoad
per recuperare eventuali account memorizzati nella cache aggiungendo questa riga dopo la corretta inizializzazione dinativeAuth
:accountResult = nativeAuth.getNativeAuthUserAccount()
.Aggiornare il gestore
signInCompleted
per archiviare il risultato dell'account:func onSignInCompleted(result: MSALNativeAuthUserAccountResult) { resultTextView.text = "Signed in successfully" accountResult = result }
Aggiungere un pulsante Disconnetti e usare il codice seguente per disconnettere l'utente:
@IBAction func signOutPressed(_: Any) { guard let accountResult = accountResult else { print("Not currently signed in") return } accountResult.signOut() self.accountResult = nil resultTextView.text = "Signed out" }
Sono stati completati tutti i passaggi necessari per disconnettere un utente nell'app. Compilare ed eseguire l'applicazione. Se tutto va bene, si dovrebbe riuscire a selezionare il pulsante Disconnetti per una corretta disconnessione.
Configurare un provider di attestazioni personalizzato
Se si desidera aggiungere attestazioni da un sistema esterno al token rilasciato all'app, usare un provider di attestazioni personalizzato. Un provider di attestazioni personalizzato è costituito da un'estensione di autenticazione personalizzata che chiama un'API REST per recuperare le attestazioni da sistemi esterni.
Seguire la procedura descritta in Configurare un provider di attestazioni personalizzato per aggiungere attestazioni da un sistema esterno ai token di sicurezza.