Condividi tramite


Validazione delle credenziali utente nello store utenti membri (C#)

di Scott Mitchell

Annotazioni

Poiché questo articolo è stato scritto, i provider di appartenenza ASP.NET sono stati sostituiti da ASP.NET Identity. Consigliamo vivamente di aggiornare le app per utilizzare la piattaforma ASP.NET Identity anziché i provider di appartenenza presenti al momento della stesura di questo articolo. ASP.NET Identity offre numerosi vantaggi rispetto al sistema di appartenenza ASP.NET, tra cui :

  • Prestazioni migliori
  • Estendibilità e testbilità migliorate
  • Supporto per OAuth, OpenID Connect e autenticazione a due fattori
  • Supporto per le identità basate su attestazioni
  • Migliore interoperabilità con ASP.Net Core

Scarica Codice o Scarica PDF

In questa esercitazione esamineremo come convalidare le credenziali di un utente rispetto all'archivio utenti del sistema di appartenenza, utilizzando sia mezzi programmatici che il controllo di accesso Login. Verrà inoltre illustrato come personalizzare l'aspetto e il comportamento del controllo di accesso.

Introduzione

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 rispetto 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 utenti. 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 questo tutorial esamineremo come convalidare le credenziali di un utente rispetto al repository utenti di Membership, usando sia i metodi programmatici che il controllo Login. Verrà inoltre illustrato come personalizzare l'aspetto e il comportamento del controllo di accesso. È ora di iniziare.

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

Per i siti Web che usano l'autenticazione basata su moduli, 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 Membership, 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.

SqlMembershipProvider convalida le credenziali fornite ottenendo la password dell'utente specificato tramite la stored procedure aspnet_Membership_GetPasswordWithFormat. 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 metodo viene trasformato nello ValidateUser stato crittografato o con 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.

Aggiorniamo la pagina di accesso (~/Login.aspx) in modo che convalidi le credenziali fornite nell'archivio utenti del framework Membership. Questa pagina di accesso è stata creata nuovamente 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 checkboxlist e un pulsante

Figura 1: L'interfaccia della pagina di accesso include due caselle di testo, un 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 di Membership Framework. Aggiornare il gestore eventi in modo che il codice venga visualizzato nel modo seguente:

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 Una panoramica dell'autenticazione basata su form, il FormsAuthentication.RedirectFromLoginPage crea 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 che informa l'utente che il nome utente o la password è incorretto.

Ecco fatto!

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.

Annotazioni

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 annusa il traffico di rete può vedere il nome utente e la password. Per evitare ciò, è essenziale crittografare il traffico di rete utilizzando Secure Socket Layers (SSL). Ciò garantirà che le credenziali (così come il markup HTML dell'intera pagina) siano crittografate dal momento in cui lasciano il browser fino a quando non vengono ricevute dal server web.

Gestione dei tentativi di accesso non validi nel framework di gestione delle appartenenze

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. Pertanto, un hacker che tenta di entrare nel sito potrebbe creare un programma che invia in modo esaustivo 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, momento in cui il programma riconosce di aver individuato una coppia valida di nome utente e password. 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 sono presenti 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 , anche se vengono fornite credenziali valide. Anche se questo comportamento riduce la probabilità che un hacker si introdurrà nel tuo sito tramite metodi di forza bruta, può portare al blocco di un utente valido che ha semplicemente dimenticato la password, ha attivato il tasto Maiusc per errore o sta avendo problemi di digitazione.

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.

Annotazioni

Uno svantaggio del ValidateUser metodo è che quando le credenziali specificate 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 utenti 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 di autenticazione esegue il rendering di un'interfaccia utente predefinita molto simile a quella che abbiamo creato nel tutorial . L'uso del controllo Login consente di risparmiare il lavoro di dover creare l'interfaccia per raccogliere le credenziali del visitatore. Inoltre, il controllo Login accede automaticamente all'utente (presupponendo che le credenziali inviate siano valide), evitando così di dover scrivere codice.

Si procederà ad aggiornare Login.aspx, sostituendo l'interfaccia creata manualmente e il codice con un controllo di accesso. Per iniziare, rimuovere il markup e il codice esistenti in Login.aspx. È possibile eliminarlo in modo definitivo o semplicemente impostarlo come commento. Per impostare come commento il markup dichiarativo, racchiuderlo con i delimitatori <%-- e --%>. È possibile immettere manualmente questi delimitatori oppure, come illustrato nella figura 2, è possibile selezionare il testo da impostare come commento e quindi fare clic sull'icona Commento per le righe selezionate nella barra degli strumenti. Analogamente, è possibile usare l'icona "Commentare 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: Commentare il markup dichiarativo esistente e il codice sorgente in Login.aspx (fare clic per visualizzare l'immagine a schermo intero)

Annotazioni

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

Trascinare quindi un controllo Login dalla Toolbox sulla pagina e impostarne la proprietà ID su myLogin. A questo punto la schermata dovrebbe essere simile alla figura 3. Si noti che l'interfaccia predefinita del controllo Login include controlli TextBox per il nome utente e la password, un controllo Memorizzami la volta successiva e un pulsante Di accesso. Sono inoltre RequiredFieldValidator disponibili 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 di accesso chiamerà il Membership.ValidateUser metodo, passando il nome utente e la password immessi. Se le credenziali non sono valide, il controllo Login visualizza un messaggio simile. Tuttavia, se le credenziali sono valide, il controllo di accesso crea il ticket di autenticazione basata su form e reindirizza l'utente alla pagina appropriata.

Il controllo di accesso utilizza quattro fattori per determinare la pagina appropriata a cui reindirizzare l'utente dopo un login riuscito.

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

La figura 4 illustra 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 Login, visitare il sito tramite un browser e accedere come utente esistente nel framework di Membership.

L'interfaccia renderizzata del controllo login è 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 predefinite delle proprietà del controllo Login generano un'interfaccia utente con un titolo (Accedi), controlli TextBox e Label per l'inserimento di nome utente e password, una casella di controllo Ricordami la prossima volta e un pulsante Accedi. Gli aspetti di questi elementi sono tutti configurabili tramite le numerose proprietà del controllo Login. Inoltre, è possibile aggiungere altri elementi dell'interfaccia utente, ad esempio un collegamento a una pagina per creare un nuovo account utente, impostando una proprietà o due.

Passiamo qualche momento per migliorare l'aspetto del nostro controllo Login. Poiché la Login.aspx pagina contiene già testo nella parte superiore della pagina che indica Login, il titolo del controllo Login è superfluo. Cancellare quindi 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. Modifichiamo l'etichetta "User Name:" per leggere "Username:". Gli stili Label e TextBox sono configurabili rispettivamente tramite le LabelStyle proprietà e TextBoxStyle.

La proprietà Text del CheckBox "Ricordami la prossima volta" può essere impostata tramite il controllo RememberMeText property Login e il suo stato selezionato predefinito è configurabile tramite RememberMeSet property, che per impostazione predefinita è False. Andare avanti e impostare la RememberMeSet proprietà su True in modo che la casella di controllo Memorizzami la volta successiva verrà selezionata per impostazione predefinita.

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

Annotazioni

Nella sezione successiva, Configurazione del Layout del Controllo di Accesso, esamineremo l'uso dei modelli per definire il layout preciso degli elementi dell'interfaccia utente del controllo di layout.

Completare le impostazioni delle proprietà del controllo di accesso impostando le proprietà CreateUserText e CreateUserUrl su Non ancora registrato? Crea un account! e ~/Membership/CreatingUserAccounts.aspx, rispettivamente. Verrà aggiunto un collegamento ipertestuale all'interfaccia del controllo Login che punta alla pagina creata precedente. Le proprietà HelpPageText e HelpPageUrl e le proprietà PasswordRecoveryText e PasswordRecoveryUrl del controllo Login funzionano nello stesso modo, generando 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 quello illustrato nella figura 5.

I valori delle proprietà del controllo di accesso ne 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 definisce l'interfaccia in un codice HTML <table>. Ma cosa accade se è necessario un controllo più dettagliato sull'output sottoposto a 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. Qualunque sia il motivo, è possibile convertire il controllo Login in un modello, da cui è possibile definire in modo esplicito il markup dichiarativo dell'interfaccia.

Per aggiornare il controllo Di accesso per raccogliere credenziali aggiuntive, è necessario eseguire due operazioni:

  1. Aggiornare l'interfaccia del controllo Login per includere i 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. Per quanto riguarda la seconda attività, la logica di autenticazione del controllo di accesso può essere sostituita creando un gestore di eventi per l'evento del controllo Authenticate.

Aggiorniamo il controllo di accesso in modo che siano richiesti agli utenti il nome utente, la password e l'indirizzo di posta elettronica, e l'utente è autenticato solo se l'indirizzo di posta elettronica fornito corrisponde ai loro dati registrati. 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)

Annotazioni

Per ripristinare la versione originale del controllo Login prima della personalizzazione modello, fare clic sul collegamento Reimposta dallo Smart Tag del controllo.

La conversione del controllo Login in un modello aggiunge un LayoutTemplate nel 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.

Sono disponibili meno proprietà quando il controllo di accesso viene convertito in un modello

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

Il markup HTML nel LayoutTemplate può essere modificato in base alle esigenze. Analogamente, è possibile aggiungere 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 TextBox, Password TextBox, il RememberMe CheckBox, il LoginButton Button, l'etichetta FailureText Label o i controlli RequiredFieldValidator.

Per raccogliere l'indirizzo di posta elettronica del visitatore, è necessario aggiungere una casella di testo al modello. Aggiungere il markup dichiarativo seguente tra la riga della tabella (<tr>) che contiene textBox Password e la riga della tabella contenente la casella di controllo Memorizzami 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 la casella di testo Email, visitare la pagina con 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 di posta elettronica dell'utente

Figura 8: Il controllo di accesso include ora una casella di testo per l'indirizzo di posta elettronica 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. Di conseguenza, il valore immesso nel Email TextBox non influisce sulla possibilità dell'utente di accedere. Nel passaggio 3 verrà illustrato come eseguire l'override della logica di autenticazione del controllo di accesso in modo che le credenziali siano 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 utente fornisce le credenziali e fa clic sul pulsante Accedi, viene eseguito un postback e il controllo di accesso passa attraverso il processo di autenticazione. Il flusso di lavoro inizia attivando l'evento LoggingIn. 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 con l'attivazione dell'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 form, viene generato l'eventoLoggedIn e l'utente viene reindirizzato alla pagina appropriata. Se, tuttavia, le credenziali vengono 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 semplicemente la proprietà Text del controllo FailureText Label su un messaggio di insuccesso ( Il tentativo di accesso non è riuscito. Riprovare ). Tuttavia, se la proprietà del controllo Login FailureAction è impostata su RedirectToLoginPage, il controllo Login emette un Response.Redirect alla pagina di accesso, aggiungendo il parametro di querystring loginfailure=1, il che fa sì che il controllo Login mostri il messaggio di errore.

La figura 9 offre un grafico 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)

Annotazioni

Se ti stai chiedendo quando utilizzare l'opzione FailureAction pagina di RedirectToLogin, considera il seguente scenario. Attualmente, la Site.master pagina master contiene il testo "Ciao, sconosciuto" visualizzato nella colonna sinistra quando viene visitata da un utente anonimo, ma immaginiamo di voler sostituire quel testo con un controllo di accesso. In questo modo un utente anonimo può 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 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 utilizzata Authenticated per specificare se le credenziali specificate sono valide. L'attività, quindi, consiste nel scrivere il codice qui che determina se le credenziali fornite sono valide o meno e impostare di conseguenza la e.Authenticate proprietà.

Determinazione e convalida delle credenziali fornite

Usare le proprietà UserName e Password del controllo Login per determinare il nome utente e la password immessi dall'utente. Per determinare i valori immessi in eventuali controlli Web aggiuntivi,ad esempio textBox Email aggiunti nel passaggio precedente, utilizzare 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:

TextBox EmailTextBox = myLogin.FindControl("Email") as TextBox;

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

  1. Verificare 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 da poterlo confrontare con l'indirizzo di posta elettronica immesso nel controllo TextBox. Per ottenere informazioni su un determinato utente, usare il Membership metodo della GetUserclasse.

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

Il codice seguente implementa questi due controlli. Se entrambi passano, e.Authenticate viene 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 questa volta usare intenzionalmente un indirizzo di posta elettronica non corretto (vedere la figura 10). Infine, provarla una terza volta usando un nome utente inesistente. Nel primo caso si dovrebbe accedere correttamente al sito, ma negli ultimi due casi dovrebbe essere visualizzato il messaggio credenziali non valido del controllo di accesso.

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

Figura 10: Tito non è in grado di accedere quando si specifica un indirizzo di posta elettronica non corretto (fare clic per visualizzare l'immagine a dimensione intera)

Annotazioni

Come illustrato nella sezione Modalità di gestione dei tentativi di accesso non validi nel passaggio 1, quando il Membership.ValidateUser metodo viene chiamato e passato credenziali non valide, tiene 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 ValidateUser metodo , una password non corretta per un nome utente valido incrementerà il 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. È probabile che questo comportamento sia adatto, poiché è improbabile che un hacker conosca il nome utente e la password, ma deve usare tecniche di forza bruta per determinare l'indirizzo di posta elettronica dell'utente.

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

Quando un utente tenta di accedere con credenziali non valide, il controllo Account di accesso visualizza un messaggio che indica che il tentativo di accesso non è riuscito. In particolare, il controllo visualizza il messaggio specificato dalla FailureText sua proprietà, che ha un valore predefinito: Il 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 (molto 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 Account di accesso visualizza lo stesso messaggio di errore. Questa mancanza di feedback può generare confusione per un utente il cui account non è ancora stato approvato o che è 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 FailureText controllo Login sul valore predefinito ( Il tentativo di accesso non è riuscito. Riprovare . Controlla quindi se il nome utente fornito corrisponde a un account utente esistente. In tal caso, consulta le proprietà IsLockedOut e IsApproved dell'oggetto MembershipUser risultante 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, tentare intenzionalmente di accedere 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 successivi tentativi di accesso avranno sempre esito negativo (anche con la password corretta), ma ora visualizzerà il più descrittivo L'account è stato bloccato a causa di troppi tentativi di accesso non validi. Contattare l'amministratore per visualizzare il messaggio di sblocco dell'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 a dimensione intera)

Sommario

Prima di questa esercitazione, la pagina di accesso convalidava le credenziali fornite in base a un elenco hardcoded di coppie nome utente/password. In questa esercitazione, abbiamo aggiornato la pagina per convalidare le credenziali rispetto al framework Membership. 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 di accesso esegue il rendering di un'interfaccia utente di accesso standard e convalida automaticamente le credenziali dell'utente rispetto al framework Membership. Inoltre, nel caso di credenziali valide, il controllo Login firma l'utente tramite l'autenticazione basata su form. In breve, un'esperienza utente di accesso completamente funzionale è disponibile semplicemente trascinando il controllo Login in una pagina, senza markup dichiarativo aggiuntivo o codice necessario. Inoltre, il controllo Login è altamente personalizzabile, consentendo un livello di controllo dettagliato sia sull'interfaccia utente di cui è stato eseguito il rendering che sulla logica di autenticazione.

A questo punto i visitatori del nostro sito Web possono creare un nuovo account utente e accedere al sito, ma dobbiamo ancora esaminare la limitazione dell'accesso alle pagine in base all'utente autenticato. Attualmente, qualsiasi utente, autenticato o anonimo, può visualizzare qualsiasi pagina nel nostro sito. Oltre a controllare l'accesso alle pagine del sito in base all'utente, potremmo avere determinate pagine la cui funzionalità dipende dall'utente. L'esercitazione successiva illustra come limitare l'accesso e la funzionalità della pagina in base all'utente loggato.

Buon programmatori!

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, formatore e scrittore. Il suo ultimo libro è Sams Teach Yourself ASP.NET 2.0 in 24 ore. Scott può essere raggiunto a mitchell@4guysfromrolla.com o tramite il suo blog all'indirizzo http://ScottOnWriting.NET.

Grazie speciale a

Questa serie di esercitazioni è stata esaminata da molti revisori competenti. I revisori principali per questo tutorial erano Teresa Murphy e Michael Olivero. Si è interessati a esaminare i prossimi articoli MSDN? In tal caso, mandami un messaggio a mitchell@4GuysFromRolla.com.