Convalida delle credenziali utente rispetto all'archivio utente di appartenenza (C#)
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 ValidateUser
classe. Il ValidateUser
metodo accetta due parametri di input e username
password
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 SqlMembershipProvider
password
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).
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 void LoginButton_Click(object sender, EventArgs e)
{
// Validate the user against the Membership framework user store
if (Membership.ValidateUser(UserName.Text, Password.Text))
{
// Log the user into the site
FormsAuthentication.RedirectFromLoginPage(UserName.Text, RememberMe.Checked);
}
// If we reach here, the user's credentials were invalid
InvalidCredentialsMessage.Visible = true;
}
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à false
sempre , 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.
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.
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 - 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.
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 il controllo RememberMeText property
Login e il relativo stato selezionato predefinito è configurabile tramite ( RememberMeSet property
il valore predefinito è 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. Indica TextLayout property
se il nome utente e la password: le etichette vengono visualizzate a sinistra delle caselle di testo corrispondenti (impostazione predefinita) o superiori. Indica Orientation property
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 PasswordRecoveryText
PasswordRecoveryUrl
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.
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:
- Aggiornare l'interfaccia del controllo Di accesso per includere controlli Web per raccogliere le credenziali aggiuntive.
- 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 Authenticate
controllo.
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.
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
, CreateUserUrl
e così via, poiché questi valori di proprietà vengono ignorati quando si usa 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.
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.
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 FailureAction
pagina 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 delAuthenticate
gestore 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 void myLogin_Authenticate(object sender, AuthenticateEventArgs e)
{
}
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.FindControl
LoginControlID
("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:
TextBox EmailTextBox = myLogin.FindControl("Email") as TextBox;
Per convalidare le credenziali dell'utente, è necessario eseguire due operazioni:
- Assicurarsi che il nome utente e la password specificati siano validi
- 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 GetUser
classe.
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
, IsApproved
Email
IsOnline
e così via.
Il codice seguente implementa questi due controlli. Se entrambi passano, e.Authenticate
è impostato su true
, in caso contrario viene assegnato false
.
protected void myLogin_Authenticate(object sender, AuthenticateEventArgs e)
{
// Get the email address entered
TextBox EmailTextBox = myLogin.FindControl("Email") as TextBox;
string email = EmailTextBox.Text.Trim();
// Verify that the username/password pair is valid
if (Membership.ValidateUser(myLogin.UserName, myLogin.Password))
{
// Username/password are valid, check email
MembershipUser usrInfo = Membership.GetUser(myLogin.UserName);
if (usrInfo != null && string.Compare(usrInfo.Email, email, true) == 0)
{
// Email matches, the credentials are valid
e.Authenticated = true;
}
else
{
// Email address is invalid...
e.Authenticated = false;
}
}
else
{
// Username/password are not valid...
e.Authenticated = false;
}
}
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.
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 void myLogin_LoginError(object sender, EventArgs e)
{
// 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?
MembershipUser usrInfo = Membership.GetUser(myLogin.UserName);
if (usrInfo != null)
{
// Is this user locked out?
if (usrInfo.IsLockedOut)
{
myLogin.FailureText = "Your account has been locked out because of too many invalid login attempts. Please contact the administrator to have your account unlocked.";
}
else if (!usrInfo.IsApproved)
{
myLogin.FailureText = "Your account has not yet been approved. You cannot login until an administrator has approved your account.";
}
}
}
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.
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:
- Visualizzazione di messaggi personalizzati per gli utenti bloccati e non approvati
- Esame dell'appartenenza, dei ruoli e del profilo di ASP.NET 2.0
- Procedura: Creare una pagina di accesso ASP.NET
- Documentazione tecnica del controllo di accesso
- Uso dei controlli di accesso
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.