Convalida delle credenziali utente rispetto all'archivio utente di appartenenza (VB)

di Scott Mitchell

Nota

Poiché questo articolo è stato scritto, i provider di appartenenze ASP.NET sono stati sostituiti da ASP.NET Identity. È consigliabile aggiornare le app per usare ASP.NET Identity Platform anziché i provider di appartenenze in primo piano al momento della scrittura di questo articolo. ASP.NET Identity presenta diversi vantaggi rispetto al sistema di appartenenza ASP.NET, tra cui :

  • Prestazioni migliori
  • Miglioramento dell'estendibilità e della testability
  • Supporto per OAuth, OpenID Connect e autenticazione a due fattori
  • Supporto delle identità basate sulle attestazioni
  • Migliore interoperabilità con ASP.Net Core

Scaricare il codice o scaricare il PDF

In questa esercitazione verrà illustrato come convalidare le credenziali di un utente rispetto all'archivio utenti di appartenenza usando sia mezzi programmatici che il controllo Di accesso. Si esaminerà anche come personalizzare l'aspetto e il comportamento del controllo di accesso.

Introduzione

Nell'esercitazione precedente è stato illustrato come creare un nuovo account utente nel framework di appartenenza. Prima di tutto è stata esaminata la creazione di account utente a livello di codice tramite il Membership metodo della CreateUser classe e quindi è stata esaminata usando il controllo Web CreateUserWizard. Tuttavia, la pagina di accesso convalida attualmente le credenziali fornite in base a un elenco hardcoded di coppie nome utente e password. È necessario aggiornare la logica della pagina di accesso in modo che convalide le credenziali rispetto all'archivio utenti del framework di appartenenza.

Analogamente alla creazione di account utente, le credenziali possono essere convalidate a livello di codice o dichiarativo. L'API di appartenenza include un metodo per convalidare a livello di codice le credenziali di un utente rispetto all'archivio utente. E ASP.NET viene fornito con il controllo Web di accesso, che esegue il rendering di un'interfaccia utente con caselle di testo per il nome utente e la password e un pulsante per l'accesso.

In questa esercitazione verrà illustrato come convalidare le credenziali di un utente rispetto all'archivio utenti di appartenenza usando sia mezzi programmatici che il controllo Di accesso. Si esaminerà anche come personalizzare l'aspetto e il comportamento del controllo di accesso. È possibile iniziare subito.

Passaggio 1: Convalida delle credenziali nell'archivio utenti di appartenenza

Per i siti Web che usano l'autenticazione basata su form, un utente accede al sito Web visitando una pagina di accesso e immettendo le proprie credenziali. Queste credenziali vengono quindi confrontate con l'archivio utenti. Se sono validi, all'utente viene concesso un ticket di autenticazione basata su form, ovvero un token di sicurezza che indica l'identità e l'autenticità del visitatore.

Per convalidare un utente rispetto al framework di appartenenza, usare il Membership metodo della ValidateUserclasse. Il ValidateUser metodo accetta due parametri di input e usernamepassword restituisce un valore booleano che indica se le credenziali sono valide. Analogamente al CreateUser metodo esaminato nell'esercitazione precedente, il ValidateUser metodo delega la convalida effettiva al provider di appartenenze configurato.

Convalida SqlMembershipProvider le credenziali fornite ottenendo la password dell'utente specificato tramite la aspnet_Membership_GetPasswordWithFormat stored procedure. Tenere presente che le SqlMembershipProvider password degli utenti vengono archiviate usando uno dei tre formati seguenti: clear, encrypted o hashed. La aspnet_Membership_GetPasswordWithFormat stored procedure restituisce la password nel formato non elaborato. Per le password crittografate o con hash, il SqlMembershipProviderpassword valore passato al ValidateUser metodo viene trasformato nello stato crittografato o hash equivalente e quindi lo confronta con quello restituito dal database. Se la password archiviata nel database corrisponde alla password formattata immessa dall'utente, le credenziali sono valide.

Aggiornare la pagina di accesso (~/Login.aspx) in modo che convalidi le credenziali fornite rispetto all'archivio utenti del framework di appartenenza. Questa pagina di accesso è stata creata di nuovo nell'esercitazione Panoramica dell'autenticazione basata su form, creando un'interfaccia con due caselle di testo per il nome utente e la password, una casella di controllo Memorizzami e un pulsante Di accesso (vedere la figura 1). Il codice convalida le credenziali immesse in base a un elenco hardcoded di coppie nome utente e password (Scott/password, Jisun/password e Sam/password).

L'interfaccia della pagina di accesso include due caselle di testo, un controllo CheckBoxList e un pulsante

Figura 1: l'interfaccia della pagina di accesso include due caselle di testo, un controllo CheckBoxList e un pulsante (fare clic per visualizzare l'immagine a dimensione intera)

L'interfaccia utente della pagina di accesso può rimanere invariata, ma è necessario sostituire il gestore eventi del Click pulsante di accesso con il codice che convalida l'utente rispetto all'archivio utenti del framework di appartenenza. Aggiornare il gestore eventi in modo che il codice venga visualizzato come segue:

Protected Sub LoginButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles LoginButton.Click

 ' Validate the user against the Membership framework user store
 If Membership.ValidateUser(UserName.Text, Password.Text) Then
 ' Log the user into the site
 FormsAuthentication.RedirectFromLoginPage(UserName.Text, RememberMe.Checked)
 End If
    
 ' If we reach here, the user's credentials were invalid
 InvalidCredentialsMessage.Visible = True
End Sub

Questo codice è notevolmente semplice. Per iniziare, chiamare il Membership.ValidateUser metodo , passando il nome utente e la password specificati. Se il metodo restituisce True, l'utente ha eseguito l'accesso al sito tramite il FormsAuthentication metodo RedirectFromLoginPage della classe. (Come abbiamo discusso in Panoramica dell'esercitazione sull'autenticazione basata su form , crea FormsAuthentication.RedirectFromLoginPage il ticket di autenticazione basata su form e quindi reindirizza l'utente alla pagina appropriata. Se le credenziali non sono valide, tuttavia, viene visualizzata l'etichetta InvalidCredentialsMessage , informando l'utente che il nome utente o la password non sono corretti.

Questo è tutto ciò che occorre fare.

Per verificare che la pagina di accesso funzioni come previsto, provare ad accedere con uno degli account utente creati nell'esercitazione precedente. In alternativa, se non è ancora stato creato un account, procedere e crearne uno dalla ~/Membership/CreatingUserAccounts.aspx pagina.

Nota

Quando l'utente immette le credenziali e invia il modulo della pagina di accesso, le credenziali, inclusa la password, vengono trasmesse tramite Internet al server Web in testo normale. Ciò significa che qualsiasi hacker che analizza il traffico di rete può visualizzare il nome utente e la password. Per evitare questo problema, è essenziale crittografare il traffico di rete usando Secure Socket Layers (SSL). In questo modo si garantisce che le credenziali (nonché il markup HTML dell'intera pagina) vengano crittografate dal momento in cui lasciano il browser fino a quando non vengono ricevute dal server Web.

Modalità di gestione dei tentativi di accesso non validi da parte del framework di appartenenza

Quando un visitatore raggiunge la pagina di accesso e invia le proprie credenziali, il browser effettua una richiesta HTTP alla pagina di accesso. Se le credenziali sono valide, la risposta HTTP include il ticket di autenticazione in un cookie. Di conseguenza, un hacker che tenta di entrare nel sito potrebbe creare un programma che invia in modo completo le richieste HTTP alla pagina di accesso con un nome utente valido e un'ipotesi alla password. Se l'ipotesi della password è corretta, la pagina di accesso restituirà il cookie del ticket di autenticazione, a quel punto il programma sa che si è verificato un errore in una coppia nome utente/password valida. Tramite forza bruta, un programma di questo tipo potrebbe essere in grado di inciampare sulla password di un utente, soprattutto se la password è debole.

Per evitare attacchi di forza bruta di questo tipo, il framework di appartenenza blocca un utente se è presente un determinato numero di tentativi di accesso non riusciti entro un determinato periodo di tempo. I parametri esatti sono configurabili tramite le due impostazioni di configurazione del provider di appartenenze seguenti:

  • maxInvalidPasswordAttempts : specifica il numero di tentativi di password non validi consentiti per l'utente entro il periodo di tempo prima che l'account venga bloccato. Il valore predefinito è 5.
  • passwordAttemptWindow - indica il periodo di tempo in minuti durante il quale il numero specificato di tentativi di accesso non validi causerà il blocco dell'account. Il valore predefinito è 10.

Se un utente è stato bloccato, non può accedere fino a quando un amministratore non sblocca il proprio account. Quando un utente è bloccato, il ValidateUser metodo restituirà Falsesempre , anche se vengono specificate credenziali valide. Anche se questo comportamento riduce la probabilità che un hacker si rompono nel tuo sito tramite metodi di forza bruta, può finire per bloccare un utente valido che ha semplicemente dimenticato la password o accidentalmente ha il caps Lock on o sta avendo un giorno di digitazione errato.

Sfortunatamente, non esiste uno strumento predefinito per sbloccare un account utente. Per sbloccare un account, è possibile modificare direttamente il database, modificare il IsLockedOut campo nella aspnet_Membership tabella per l'account utente appropriato oppure creare un'interfaccia basata sul Web che elenca gli account bloccati con opzioni per sbloccarli. Verrà esaminata la creazione di interfacce amministrative per eseguire attività comuni relative all'account utente e ai ruoli in un'esercitazione futura.

Nota

Uno svantaggio del ValidateUser metodo è che quando le credenziali fornite non sono valide, non fornisce alcuna spiegazione sul motivo. Le credenziali potrebbero non essere valide perché non esiste alcuna coppia nome utente/password corrispondente nell'archivio utente o perché l'utente non è ancora stato approvato o perché l'utente è stato bloccato. Nel passaggio 4 verrà illustrato come visualizzare un messaggio più dettagliato all'utente quando il tentativo di accesso ha esito negativo.

Passaggio 2: Raccolta di credenziali tramite il controllo Web di accesso

Il controllo Web Login esegue il rendering di un'interfaccia utente predefinita molto simile a quella creata nell'esercitazione Panoramica dell'autenticazione basata su form. L'uso del controllo Login consente di salvare il lavoro di dover creare l'interfaccia per raccogliere le credenziali del visitatore. Inoltre, il controllo Login esegue automaticamente l'accesso all'utente (presupponendo che le credenziali inviate siano valide), evitando così di dover scrivere codice.

Si aggiorni Login.aspx, sostituendo l'interfaccia e il codice creati manualmente con un controllo Login. Per iniziare, rimuovere il markup e il codice esistenti in Login.aspx. È possibile eliminarlo in modo definitivo o semplicemente commentarlo. Per impostare come commento il markup dichiarativo, racchiuderlo tra i <%-- delimitatori e --%> . È possibile immettere questi delimitatori manualmente oppure, come illustrato nella figura 2, è possibile selezionare il testo da impostare come commento e quindi fare clic sull'icona Commento sulle righe selezionate nella barra degli strumenti. Analogamente, è possibile usare l'icona Imposta come commento le righe selezionate per impostare come commento il codice selezionato nella classe code-behind.

Impostare come commento il markup dichiarativo esistente e il codice sorgente in Login.aspx

Figura 2: Impostare come commento il markup dichiarativo esistente e il codice sorgente in Login.aspx (fare clic per visualizzare l'immagine a dimensione intera)

Nota

L'icona Commenta le righe selezionate non è disponibile quando si visualizza il markup dichiarativo in Visual Studio 2005. Se non si usa Visual Studio 2008, è necessario aggiungere manualmente i <%-- delimitatori e --%> .

Trascinare quindi un controllo Login dalla Casella degli strumenti nella pagina e impostarne la ID proprietà su myLogin. A questo punto lo schermo dovrebbe essere simile alla figura 3. Si noti che l'interfaccia predefinita del controllo Login include i controlli TextBox per il nome utente e la password, una casella di controllo Ricordami la volta successiva e un pulsante Di accesso. Sono disponibili anche RequiredFieldValidator controlli per le due caselle di testo.

Aggiungere un controllo di accesso alla pagina

Figura 3: Aggiungere un controllo di accesso alla pagina (fare clic per visualizzare l'immagine a dimensione intera)

E abbiamo finito! Quando si fa clic sul pulsante Accedi del controllo di accesso, verrà eseguito un postback e il controllo Login chiamerà il Membership.ValidateUser metodo , passando il nome utente e la password immessi. Se le credenziali non sono valide, il controllo Account di accesso visualizza un messaggio simile. Se, tuttavia, le credenziali sono valide, il controllo Account di accesso crea il ticket di autenticazione basata su form e reindirizza l'utente alla pagina appropriata.

Il controllo Account di accesso usa quattro fattori per determinare la pagina appropriata per reindirizzare l'utente a in caso di accesso riuscito:

  • Indica se il controllo Account di accesso si trova nella pagina di accesso come definito dall'impostazione loginUrl nella configurazione dell'autenticazione basata su form. Il valore predefinito di questa impostazione è Login.aspx
  • Presenza di un ReturnUrl parametro querystring
  • Valore della proprietà del DestinationUrl controllo Login
  • Il valore specificato nelle impostazioni di configurazione dell'autenticazione basata su form. Il defaultUrl valore predefinito di questa impostazione è Default.aspx

Nella figura 4 viene illustrato il modo in cui il controllo Login usa questi quattro parametri per arrivare alla decisione di pagina appropriata.

Il controllo Login usa quattro parametri per arrivare alla decisione di pagina appropriata.

Figura 4: Aggiungere un controllo di accesso alla pagina (fare clic per visualizzare l'immagine a dimensione intera)

Per testare il controllo di accesso, visitare il sito tramite un browser e accedere come utente esistente nel framework di appartenenza.

L'interfaccia di cui è stato eseguito il rendering del controllo di accesso è altamente configurabile. Ci sono una serie di proprietà che influenzano il suo aspetto; inoltre, il controllo Login può essere convertito in un modello per un controllo preciso sul layout degli elementi dell'interfaccia utente. Il resto di questo passaggio esamina come personalizzare l'aspetto e il layout.

Personalizzazione dell'aspetto del controllo di accesso

Le impostazioni delle proprietà predefinite del controllo Login eseguono il rendering di un'interfaccia utente con un titolo ( Log In ), TextBox e Label per gli input di nome utente e password, un controllo Memorizzami la volta successiva e un pulsante Accedi. Gli aspetti di questi elementi sono tutti configurabili tramite le numerose proprietà del controllo Login. Inoltre, è possibile aggiungere elementi aggiuntivi dell'interfaccia utente, ad esempio un collegamento a una pagina per creare un nuovo account utente, impostando una proprietà o due.

Passiamo alcuni istanti per sgorgare l'aspetto del controllo Login. Poiché la Login.aspx pagina contiene già testo nella parte superiore della pagina che indica Login, il titolo del controllo Login è superfluo. Di conseguenza, cancellare il valore della TitleText proprietà per rimuovere il titolo del controllo Login.

Nome utente: e Password: le etichette a sinistra dei due controlli TextBox possono essere personalizzate rispettivamente tramite le UserNameLabelText proprietà e PasswordLabelText. Modificare il nome utente: etichetta per leggere Username:. Gli stili Label e TextBox sono configurabili rispettivamente tramite le LabelStyle proprietà e TextBoxStyle.

La proprietà Remember me next time CheckBox's Text può essere impostata tramite la proprietà del RememberMeTextcontrollo Login e il relativo stato selezionato predefinito è configurabile tramite la RememberMeSet proprietà , che per impostazione predefinita è False. Andare avanti e impostare la RememberMeSet proprietà su True in modo che la casella di controllo Ricordami la prossima volta che checkBox verrà selezionata per impostazione predefinita.

Il controllo Login offre due proprietà per regolare il layout dei controlli dell'interfaccia utente. La TextLayout proprietà indica se il nome utente e la password: le etichette vengono visualizzate a sinistra delle caselle di testo corrispondenti (impostazione predefinita) o superiori. La Orientation proprietà indica se gli input di nome utente e password si trovano verticalmente (uno sopra l'altro) o orizzontalmente. Lascerò queste due proprietà impostate sulle impostazioni predefinite, ma vi invito a provare a impostare queste due proprietà sui valori non predefiniti per vedere l'effetto risultante.

Nota

Nella sezione successiva Verrà illustrato come configurare il layout del controllo di accesso usando i modelli per definire il layout preciso degli elementi dell'interfaccia utente del controllo Layout.

Eseguire il wrapping delle impostazioni delle proprietà del controllo di accesso impostando le CreateUserText proprietà e CreateUserUrl su Non ancora registrato? Creare un account. e ~/Membership/CreatingUserAccounts.aspx, rispettivamente. Verrà aggiunto un collegamento ipertestuale all'interfaccia del controllo Di accesso che punta alla pagina creata nell'esercitazione precedente. Le proprietà e HelpPageUrl e PasswordRecoveryTextPasswordRecoveryUrl le proprietà del HelpPageText controllo Di accesso funzionano nello stesso modo, eseguendo il rendering dei collegamenti a una pagina della Guida e a una pagina di ripristino della password.

Dopo aver apportato queste modifiche alle proprietà, il markup dichiarativo e l'aspetto del controllo di accesso dovrebbero essere simili a quanto illustrato nella figura 5.

I valori delle proprietà del controllo di accesso determinano l'aspetto

Figura 5: I valori delle proprietà del controllo di accesso determinano l'aspetto (fare clic per visualizzare l'immagine a dimensione intera)

Configurazione del layout del controllo di accesso

L'interfaccia utente predefinita del controllo Web di accesso dispone l'interfaccia in un codice HTML <table>. Ma cosa accade se è necessario un controllo più corretto sull'output di cui è stato eseguito il rendering? Forse vogliamo sostituire con <table> una serie di <div> tag. Oppure cosa accade se l'applicazione richiede credenziali aggiuntive per l'autenticazione? Molti siti Web finanziari, ad esempio, richiedono agli utenti di fornire non solo un nome utente e una password, ma anche un PIN (Personal Identification Number) o altre informazioni di identificazione. Indipendentemente dai motivi, è possibile convertire il controllo Login in un modello, da cui è possibile definire in modo esplicito il markup dichiarativo dell'interfaccia.

È necessario eseguire due operazioni per aggiornare il controllo Di accesso per raccogliere credenziali aggiuntive:

  1. Aggiornare l'interfaccia del controllo Di accesso per includere controlli Web per raccogliere le credenziali aggiuntive.
  2. Eseguire l'override della logica di autenticazione interna del controllo di accesso in modo che un utente venga autenticato solo se il nome utente e la password sono validi e anche le credenziali aggiuntive sono valide.

Per eseguire la prima attività, è necessario convertire il controllo Login in un modello e aggiungere i controlli Web necessari. Come per la seconda attività, la logica di autenticazione del controllo di accesso può essere sostituita creando un gestore eventi per l'evento del Authenticatecontrollo.

Aggiornare il controllo Account di accesso in modo da richiedere agli utenti il nome utente, la password e l'indirizzo di posta elettronica e autenticare l'utente solo se l'indirizzo di posta elettronica specificato corrisponde al proprio indirizzo di posta elettronica nel file. Prima di tutto è necessario convertire l'interfaccia del controllo Login in un modello. Dallo Smart Tag del controllo Di accesso scegliere l'opzione Converti in modello.

Convertire il controllo di accesso in un modello

Figura 6: Convertire il controllo di accesso in un modello (fare clic per visualizzare l'immagine a dimensione intera)

Nota

Per ripristinare la versione pre-modello del controllo Login, fare clic sul collegamento Reimposta dallo Smart Tag del controllo.

La conversione del controllo Login in un modello aggiunge un LayoutTemplate oggetto al markup dichiarativo del controllo con elementi HTML e controlli Web che definiscono l'interfaccia utente. Come illustrato nella figura 7, la conversione del controllo in un modello rimuove una serie di proprietà dalla Finestra Proprietà, ad esempio TitleText, CreateUserUrle così via, poiché questi valori di proprietà vengono ignorati quando si usa un modello.

Meno proprietà sono disponibili quando il controllo di accesso viene convertito in un modello

Figura 7: Sono disponibili meno proprietà quando il controllo di accesso viene convertito in un modello (fare clic per visualizzare l'immagine a dimensione intera)

Il markup HTML in LayoutTemplate può essere modificato in base alle esigenze. Allo stesso modo, è possibile aggiungere tutti i nuovi controlli Web al modello. È tuttavia importante che i controlli Web principali del controllo di accesso rimangano nel modello e mantengano i valori assegnati ID . In particolare, non rimuovere o rinominare i UserName controlli o Password TextBoxes, RememberMe CheckBox, LoginButton Button, FailureText Label o .RequiredFieldValidator

Per raccogliere l'indirizzo di posta elettronica del visitatore, è necessario aggiungere un controllo TextBox al modello. Aggiungere il markup dichiarativo seguente tra la riga della tabella (<tr>) che contiene textBox Password e la riga della tabella che contiene la casella di controllo Ricordami la volta successiva:

<tr>
 <td align="right">
 <asp:Label ID="EmailLabel" runat="server" AssociatedControlID="Email">Email:</asp:Label>
 </td>
 <td>
 <asp:TextBox ID="Email" runat="server"></asp:TextBox>
 <asp:RequiredFieldValidator ID="EmailRequired" runat="server"
 ControlToValidate="Email" ErrorMessage="Email is required."
 ToolTip="Email is required." ValidationGroup="myLogin">*</asp:RequiredFieldValidator>
 </td>
</tr>

Dopo aver aggiunto textBox Email , visitare la pagina tramite un browser. Come illustrato nella figura 8, l'interfaccia utente del controllo Login include ora una terza casella di testo.

Il controllo Login include ora una casella di testo per l'indirizzo Email dell'utente

Figura 8: Il controllo Di accesso include ora una casella di testo per l'indirizzo di Email dell'utente (fare clic per visualizzare l'immagine a dimensione intera)

A questo punto, il controllo Login usa ancora il Membership.ValidateUser metodo per convalidare le credenziali fornite. In modo corrispondente, il valore immesso nel Email controllo TextBox non ha alcun effetto sul fatto che l'utente possa accedere. Nel passaggio 3 verrà illustrato come eseguire l'override della logica di autenticazione del controllo di accesso in modo che le credenziali vengano considerate valide solo se il nome utente e la password sono validi e l'indirizzo di posta elettronica fornito corrisponde all'indirizzo di posta elettronica nel file.

Passaggio 3: Modifica della logica di autenticazione del controllo di accesso

Quando un visitatore fornisce le credenziali e fa clic sul pulsante Accedi, viene eseguito un postback e il controllo Di accesso passa attraverso il flusso di lavoro di autenticazione. Il flusso di lavoro inizia generando l'eventoLoggingIn . Tutti i gestori eventi associati a questo evento possono annullare l'operazione di accesso impostando la e.Cancel proprietà su True.

Se l'operazione di accesso non viene annullata, il flusso di lavoro procede generando l'eventoAuthenticate . Se è presente un gestore eventi per l'evento Authenticate , è responsabile di determinare se le credenziali fornite sono valide o meno. Se non viene specificato alcun gestore eventi, il controllo Login usa il Membership.ValidateUser metodo per determinare la validità delle credenziali.

Se le credenziali specificate sono valide, viene creato il ticket di autenticazione dei moduli, viene generato l'eventoLoggedIn e l'utente viene reindirizzato alla pagina appropriata. Se, tuttavia, le credenziali sono considerate non valide, viene generato l'eventoLoginError e viene visualizzato un messaggio che informa l'utente che le credenziali non sono valide. Per impostazione predefinita, in caso di errore, il controllo Login imposta FailureText semplicemente la proprietà Text del controllo Label su un messaggio di errore ( Il tentativo di accesso non è riuscito. Riprovare . Tuttavia, se la proprietà del FailureAction controllo Login è impostata su RedirectToLoginPage, il controllo Login invia un Response.Redirect oggetto alla pagina di accesso aggiungendo il parametro loginfailure=1 querystring , che fa sì che il controllo Login visualizzi il messaggio di errore.

La figura 9 offre un diagramma di flusso del flusso di lavoro di autenticazione.

Flusso di lavoro di autenticazione del controllo di accesso

Figura 9: Flusso di lavoro di autenticazione del controllo di accesso (fare clic per visualizzare l'immagine a dimensione intera)

Nota

Se ci si chiede quando si usa l'opzione FailureActionpagina di RedirectToLogin , considerare lo scenario seguente. Attualmente la pagina Site.master master contiene il testo Hello, sconosciuto visualizzato nella colonna sinistra quando viene visitato da un utente anonimo, ma si supponga di voler sostituire il testo con un controllo Login. Ciò consentirebbe a un utente anonimo di accedere da qualsiasi pagina del sito, invece di richiedere loro di visitare direttamente la pagina di accesso. Tuttavia, se un utente non è riuscito ad accedere tramite il controllo Di accesso di cui è stato eseguito il rendering dalla pagina master, potrebbe essere opportuno reindirizzarli alla pagina di accesso (Login.aspx) perché tale pagina include probabilmente istruzioni aggiuntive, collegamenti e altre informazioni, ad esempio collegamenti per creare un nuovo account o recuperare una password persa, che non sono state aggiunte alla pagina master.

Creazione delAuthenticategestore eventi

Per collegare la logica di autenticazione personalizzata, è necessario creare un gestore eventi per l'evento del Authenticate controllo Login. La creazione di un gestore eventi per l'evento Authenticate genererà la definizione del gestore eventi seguente:

Protected Sub myLogin_Authenticate(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.AuthenticateEventArgs) Handles myLogin.Authenticate

End Sub

Come si può notare, il Authenticate gestore eventi viene passato un oggetto di tipo AuthenticateEventArgs come secondo parametro di input. La AuthenticateEventArgs classe contiene una proprietà booleana denominata Authenticated utilizzata per specificare se le credenziali specificate sono valide. L'attività, quindi, consiste nel scrivere codice qui che determina se le credenziali specificate sono valide o meno e per impostare di conseguenza la e.Authenticate proprietà.

Determinazione e convalida delle credenziali fornite

Usare le proprietà e Password il controllo UserName di accesso per determinare il nome utente e le credenziali della password immessi dall'utente. Per determinare i valori immessi in eventuali controlli Web aggiuntivi ,ad esempio Email TextBox aggiunti nel passaggio precedente, usare LoginControlID.FindControl("controlID") per ottenere un riferimento programmatico al controllo Web nel modello la cui ID proprietà è uguale a controlID. Ad esempio, per ottenere un riferimento a Email TextBox, usare il codice seguente:

Dim EmailTextBox As TextBox = CType(myLogin.FindControl("Email"), TextBox)

Per convalidare le credenziali dell'utente, è necessario eseguire due operazioni:

  1. Assicurarsi che il nome utente e la password specificati siano validi
  2. Assicurarsi che l'indirizzo di posta elettronica immesso corrisponda all'indirizzo di posta elettronica nel file per l'utente che tenta di accedere

Per eseguire il primo controllo è sufficiente usare il Membership.ValidateUser metodo come illustrato nel passaggio 1. Per il secondo controllo, è necessario determinare l'indirizzo di posta elettronica dell'utente in modo che sia possibile confrontarlo con l'indirizzo di posta elettronica immesso nel controllo TextBox. Per ottenere informazioni su un determinato utente, usare il Membership metodo della GetUserclasse.

Il GetUser metodo ha un numero di overload. Se usato senza passare i parametri, restituisce informazioni sull'utente attualmente connesso. Per ottenere informazioni su un determinato utente, chiamare GetUser il passaggio del nome utente. In entrambi i casi, GetUser restituisce un MembershipUser oggetto, con proprietà come UserName, IsApprovedEmailIsOnlinee così via.

Il codice seguente implementa questi due controlli. Se entrambi passano, e.Authenticate è impostato su True, in caso contrario viene assegnato False.

Protected Sub myLogin_Authenticate(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.AuthenticateEventArgs) Handles myLogin.Authenticate
    
 ' Get the email address entered
 Dim EmailTextBox As TextBox = CType(myLogin.FindControl("Email"), TextBox)
 Dim email As String = EmailTextBox.Text.Trim()
    
 ' Verify that the username/password pair is valid
 If Membership.ValidateUser(myLogin.UserName, myLogin.Password) Then

 ' Username/password are valid, check email
 Dim usrInfo As MembershipUser = Membership.GetUser(myLogin.UserName)
    
 If usrInfo IsNot Nothing AndAlso String.Compare(usrInfo.Email, email, True) = 0 Then
 ' Email matches, the credentials are valid
 e.Authenticated = True
 Else
 ' Email address is invalid...
 e.Authenticated = False
 End If
 Else
 ' Username/password are not valid...
 e.Authenticated = False
 End If
End Sub

Con questo codice sul posto, tentare di accedere come utente valido, immettendo il nome utente, la password e l'indirizzo di posta elettronica corretti. Riprovare, ma questo tempo usa in modo intenzionale un indirizzo di posta elettronica errato (vedere la figura 10). Infine, provare una terza volta usando un nome utente non esistente. Nel primo caso è necessario accedere correttamente al sito, ma negli ultimi due casi verrà visualizzato il messaggio di credenziali non valido del controllo di accesso.

Tito non è in grado di accedere quando si specifica un indirizzo di Email non corretto

Figura 10: Tito non è in grado di accedere quando si specifica un indirizzo di Email non corretto (fare clic per visualizzare l'immagine a dimensioni complete)

Nota

Come illustrato nella sezione How the Membership Framework Handle Invalid Login Attempts (Tentativi di accesso non validi) nel passaggio 1, quando il Membership.ValidateUser metodo viene chiamato e passato credenziali non valide, mantiene traccia del tentativo di accesso non valido e blocca l'utente se supera una determinata soglia di tentativi non validi entro un intervallo di tempo specificato. Poiché la logica di autenticazione personalizzata chiama il metodo, una password errata per un nome utente valido incrementerà il ValidateUser contatore dei tentativi di accesso non validi, ma questo contatore non viene incrementato nel caso in cui il nome utente e la password siano validi, ma l'indirizzo di posta elettronica non è corretto. Le probabilità sono, questo comportamento è adatto, poiché è improbabile che un hacker conoscerà il nome utente e la password, ma devono usare tecniche di forza bruta per determinare l'indirizzo di posta elettronica dell'utente.

Passaggio 4: Miglioramento del messaggio di credenziali non valido del controllo di accesso

Quando un utente tenta di accedere con credenziali non valide, il controllo Login visualizza un messaggio che spiega che il tentativo di accesso non è riuscito. In particolare, il controllo visualizza il messaggio specificato dalla relativaFailureText proprietà, con un valore predefinito del tentativo di accesso non riuscito. Riprova.

Tenere presente che esistono molti motivi per cui le credenziali di un utente potrebbero non essere valide:

  • Il nome utente potrebbe non esistere
  • Il nome utente esiste, ma la password non è valida
  • Il nome utente e la password sono validi, ma l'utente non è ancora approvato
  • Il nome utente e la password sono validi, ma l'utente è bloccato (probabilmente perché ha superato il numero di tentativi di accesso non validi entro l'intervallo di tempo specificato)

E potrebbero esserci altri motivi quando si usa la logica di autenticazione personalizzata. Ad esempio, con il codice scritto nel passaggio 3, il nome utente e la password possono essere validi, ma l'indirizzo di posta elettronica potrebbe non essere corretto.

Indipendentemente dal motivo per cui le credenziali non sono valide, il controllo Login visualizza lo stesso messaggio di errore. Questa mancanza di feedback può essere confusa per un utente il cui account non è ancora stato approvato o chi è stato bloccato. Con un po' di lavoro, tuttavia, è possibile che il controllo Login visualizzi un messaggio più appropriato.

Ogni volta che un utente tenta di accedere con credenziali non valide, il controllo Login genera l'evento LoginError . Procedere e creare un gestore eventi per questo evento e aggiungere il codice seguente:

Protected Sub myLogin_LoginError(ByVal sender As Object, ByVal e As System.EventArgs) Handles myLogin.LoginError
    
 ' Determine why the user could not login...
 myLogin.FailureText = "Your login attempt was not successful. Please try again."
    
 ' Does there exist a User account for this user?
 Dim usrInfo As MembershipUser = Membership.GetUser(myLogin.UserName)

 If usrInfo IsNot Nothing Then
 ' Is this user locked out?
 If usrInfo.IsLockedOut Then
 myLogin.FailureText = "Your account has been locked out because of too many invalid login attempts. Please contact the administrator to have your account unlocked."
 ElseIf Not usrInfo.IsApproved Then
 myLogin.FailureText = "Your account has not yet been approved. You cannot login until an administrator has approved your account."
 End If
 End If
End Sub

Il codice precedente inizia impostando la proprietà del controllo Login sul valore predefinito ( Il tentativo di FailureText accesso non è riuscito. Riprovare . Verifica quindi se il nome utente fornito esegue il mapping a un account utente esistente. In tal caso, consulta le proprietà e IsApproved dell'oggetto IsLockedOut risultante MembershipUser per determinare se l'account è stato bloccato o non è ancora stato approvato. In entrambi i casi, la FailureText proprietà viene aggiornata a un valore corrispondente.

Per testare questo codice, provare a eseguire l'accesso come utente esistente, ma usare una password non corretta. Eseguire questa operazione cinque volte in una riga entro un intervallo di tempo di 10 minuti e l'account verrà bloccato. Come illustrato nella figura 11, i tentativi di accesso successivi avranno sempre esito negativo (anche con la password corretta), ma ora visualizzeranno l'account più descrittivo è stato bloccato a causa di troppi tentativi di accesso non validi. Contattare l'amministratore per avere il messaggio sbloccato dall'account.

Tito ha eseguito troppi tentativi di accesso non validi ed è stato bloccato

Figura 11: Tito ha eseguito troppi tentativi di accesso non validi ed è stato bloccato (fare clic per visualizzare l'immagine full-size)

Riepilogo

Prima di questa esercitazione, la pagina di accesso convalidava le credenziali fornite in un elenco hardcoded di coppie nome utente/password. In questa esercitazione è stata aggiornata la pagina per convalidare le credenziali rispetto al framework di appartenenza. Nel passaggio 1 è stato esaminato l'uso del Membership.ValidateUser metodo a livello di codice. Nel passaggio 2 è stata sostituita l'interfaccia utente creata manualmente e il codice con il controllo Login.

Il controllo Login esegue il rendering di un'interfaccia utente di accesso standard e convalida automaticamente le credenziali dell'utente nel framework Di appartenenza. Inoltre, in caso di credenziali valide, il controllo Login firma l'utente tramite l'autenticazione dei moduli. In breve, un'esperienza utente di accesso completamente funzionale è disponibile semplicemente trascinando il controllo Login in una pagina, senza markup dichiarativo o codice aggiuntivo necessario. Inoltre, il controllo Login è altamente personalizzabile, consentendo un grado di controllo fine sia sull'interfaccia utente che sulla logica di autenticazione di cui è stato eseguito il rendering.

A questo punto i visitatori del sito Web possono creare un nuovo account utente e accedere al sito, ma è ancora necessario esaminare la limitazione dell'accesso alle pagine in base all'utente autenticato. Attualmente, qualsiasi utente, autenticato o anonimo, può visualizzare qualsiasi pagina nel sito. Oltre a controllare l'accesso alle pagine del sito in base all'utente, potrebbero essere presenti alcune pagine la cui funzionalità dipende dall'utente. L'esercitazione successiva illustra come limitare l'accesso e la funzionalità nella pagina in base all'utente connesso.

Programmazione felice!

Altre informazioni

Per altre informazioni sugli argomenti illustrati in questa esercitazione, vedere le risorse seguenti:

Informazioni sull'autore

Scott Mitchell, autore di più libri ASP/ASP.NET e fondatore di 4GuysFromRolla.com, ha lavorato con le tecnologie Web Microsoft dal 1998. Scott lavora come consulente indipendente, allenatore e scrittore. Il suo ultimo libro è Sams Teach Yourself ASP.NET 2,0 in 24 Ore. Scott può essere raggiunto all'indirizzo mitchell@4guysfromrolla.com o tramite il suo blog all'indirizzo http://ScottOnWriting.NET.

Grazie speciali

Questa serie di esercitazioni è stata esaminata da molti revisori utili. I revisori principali per questa esercitazione erano Teresa Murphy e Michael Olivero. Interessati a esaminare i prossimi articoli MSDN? In tal caso, lasciami una riga in mitchell@4GuysFromRolla.com.