In ASP.NET 2.0 la Microsoft ha aggiunto o migliorato molti controlli, quasi cinquanta, per consentire allo sviluppatore di effettuare meglio ed in meno tempo molte funzioni di uso comune. Una delle funzioni che è stata rivista in maniera più pesante è quella di autenticazione ed autorizzazione dell'utente. Per chi non lo sapesse ricordo che l'autorizzazione è quel processo composto da procedure attraverso le quali riconoscere un utente della nostra applicazione, la forma più comune è un form dove inserire username e password, mentre l'autorizzazione è composta da tutti quei processi che verificano volta per volta cosa un utente può fare e cosa no.
Sebbene i servizi di autenticazione siano rimasti invariati dalla precedente versione di ASP.NET tutta la fase di gestione dell'utente è stata ampliata con dei controlli chiamati 'Login Control'. Questi nuovi controlli generano in automatico tutto il codice di cui abbiamo bisogno per le operazioni che fino ad ora ogni programmatore ha dovuto riscrivere volta per volta per ogni sua applicazione. Come avrete capito stiamo parlando della pagina di registrazione utente, del login, del cambio e del recupero della password. Inoltre sono stati aggiunti dei controlli per mostrare il nome dell'utente loggato e per mostrare la classifica scritta 'Login' se non autenticato e 'Logout' se autenticati.
Ma la novità più importante a livello architetturale sono le nuove classi 'Membership' e 'RoleManager' che a loro volta contengono le classi 'MembershipUser' una e 'Roles' l'altra. Grazie a queste nuove classi potremo intervenire sui nostri utenti in maniera sicura e senza dover scrivere tutte le volte un sistema di gestione. Attraverso la classe 'MembershipUser', che altro non è che un'istanza di ogni singolo utente, potremo creare, modificare, eliminare, bloccare gli utenti, mentre la classe 'Membership' ci permetterà per esempio di cercarli e contarli. Le istanze degli utenti hanno per 'Default' delle proprietà molto interessanti:
- IsOnline, per sapere se un utente è attualmente sul sito
- IsApproved, per conoscere lo stato di una registrazione pendente come può accadere nei forum moderati
- IsLockedOut, ovvero bannato.
oltre a queste abbiamo i dati di registrazione, di ultimo accesso, di ultimo 'ban' e dell'ultima operazione effettuata.
Le classi per la gestione dei ruoli hanno invece il compito di garantire la sicurezza all'interno dell'applicazione, devono dunque garantire che solo agli utenti appartenenti a dei ruoli predeterminati sia consentita l'esecuzione di specifiche operazioni. Questa autorizzazione può essere concessa pagina per pagina attraverso il comando 'User.IsInRole' oppure per pagine e/o directory all'interno del 'Web.Config'.
<location path="pannellodicontrollo">
<system.web>
<authorization>
<allow roles="Gestore" />
<deny users="*"/>
</authorization>
</system.web>
</location>
in questo modo soltanto gli utenti appartenenti al ruolo di 'Gestore' possono entrare nella directory 'pannellodicontrollo.'. Vi ricordo che l'ordine delle parole chiave 'allow' e 'deny' è importante, nel nostro caso infatti invertirle non permetterebbe a nessuno di entrare del 'pannellodicontrollo'. I simboli per l'autorizzazione sono:
- Asterisco (*) per tutti gli utenti
- Punto interrogativo (?) per gli utenti anonimi
Anche le classi di gestione dei ruoli mettono a disposizione metodi e proprietà per gestire i ruoli esattamente come le classi di gestione dell'autorizzazione.
Prima di iniziare a vedere come funzionano i 'Login Control' dobbiamo configurare il 'Web.Config' della nostra applicazione per la gestione degli utenti e dei profili di cui abbiamo appena parlato.
Questo codice dice al compilatore che la fase di autenticazione viene gestita da un Form che si trova all'indirizzo 'Login.aspx'
<authentication mode="Forms">
<forms name=".ASPXAUTH"
loginUrl="Login.aspx"
protection="All"
timeout="30"
path="/"
requireSSL="false"
slidingExpiration="true"
defaultUrl="Login.aspx"
cookieless="UseDeviceProfile"
enableCrossAppRedirects="false"/>
</authentication>
Questo è il codice che definisce il gestore di 'membership' ed il relativo 'provider'.
<membership defaultProvider="QuickStartMembershipSqlProvider"
userIsOnlineTimeWindow="15">
<providers>
<add
name="QuickStartMembershipSqlProvider"
type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="ASPNETDB"
enablePasswordRetrieval="false"
enablePasswordReset="true"
requiresQuestionAndAnswer="true"
applicationName="SecurityQuickStart"
requiresUniqueEmail="true"
passwordFormat="Hashed"/>
</providers>
</membership>
ed infine abbiamo la definizione del 'roleManager' e del suo 'provider'.
<roleManager
enabled="true"
cacheRolesInCookie="true"
defaultProvider="QuickStartRoleManagerSqlProvider"
cookieName=".ASPXROLES"
cookiePath="/"
cookieTimeout="30"
cookieRequireSSL="false"
cookieSlidingExpiration="true"
createPersistentCookie="false"
cookieProtection="All">
<providers>
<add name="QuickStartRoleManagerSqlProvider"
type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="ASPNETDB"
applicationName="SecurityQuickStart"/>
</providers>
</roleManager>
In questo caso il tutto viene gestito tramite SQL Server come notiamo dalle stringhe 'connectionStringName' presenti nelle definizioni dei vari provider. Come è facilmente intuibile possiamo definire più di un provider e passare da uno all'altro senza problemi. Per una lista completa di tutti i comandi supportati si rimanda alla consultazione della guida.Oltre alla modifica manuale del 'Web.Config' la Microsoft offre all'interno di Visual Web Developer (VWD) una sezione chiamata 'ASP.NET Configuration Tool' che ci guiderà attraverso delle maschere in tutto il processo.
Una volta aver configurato la nostra applicazione iniziamo a vedere in dettaglio i 'Login Control'. Il primo 'Login Control' è 'CreateUserWizard', questo controllo ci permetterà di creare i nostri utenti. 'CreateUserWizard' ha al suo interno altri due controlli: 'CreateUserWizardStep' che genererà il form da compilare e 'CompleteWizardStep' per visualizzare dei messaggi alla fine della fase di creazione.
<asp:CreateUserWizard ID="CreateUserWizard1" runat="server">
<WizardSteps>
<asp:CreateUserWizardStep runat="server" />
<asp:CompleteWizardStep runat="server" />
</WizardSteps>
</asp:CreateUserWizard>
Il controllo 'CreateUserWizardStep' per 'Default' creerà una maschera nella quale inserire il nome utente, due volte la password di almeno sette caratteri di cui uno non ascii, un indirizzo email, la domanda segreta e la sua risposta per il recupero della password nulla ci vieterà di però di creare un nuovo controllo che lo erediti e di modificarne il comportamento secondo le nostre esigenze.
Il controllo 'ChangePassword' per cambiare la password:
<asp:ChangePassword ID="ChangePassword1" runat="server" />
</asp:ChangePassword>
Il controllo 'PasswordRecovery' per recuperare la password:
<asp:PasswordRecovery ID="PasswordRecovery1" runat="server" />
</asp:PasswordRecovery>
Il controllo 'Login' per visualizzare l'apposito form:
<asp:Login ID="Login1" runat="server" />
</asp:Login>
Il controllo 'LoginStatus' per visualizzare i comandi di 'Login' o 'Logout' secondo lo stato corrente dell'utente:
<asp:LoginStatus ID="LoginStatus1" runat="server">
</asp:LoginStatus>
Il controllo 'LoginView' per visualizzare parti personalizzate secondo lo stato dell'utente:
<asp:LoginView ID="LoginView1" runat="server">
<LoggedInTemplate>
...
</LoggedInTemplate>
<AnonymousTemplate>
...
</AnonymousTemplate>
</asp:LoginView>
Ed infine il controllo 'LoginName' che ci permetterà di non dovere più usare la 'Session' per l'ormai consueta abitudine di mostrare il nome dell'utente autenticato.
<asp:LoginName ID="LoginName1" runat="server" />
</asp:LoginName>
In realtà l'oggetto 'Session' non dovrebbe essere più utilizzato per associare dei dati temporanei all'utente ma andrebbe creato un oggetto 'MembershipUser' personalizzato, così facendo oltre ad avere l'aiuto dell'Intellisense di Visual Web Developer (VWD) ed una migliore strutturazione del codice ne guadagneremo anche in velocità. Infatti gli oggetti 'Session' vengono creati e 'trasportati' per tutta la durata della sessione dell'utente, l'oggetto 'MembershipUser' invece recupera i dati in esso contenuto ad ogni singola richiesta.
Grazie ai nuovi 'Login Control' la nostra applicazione sarà messa al sicuro in maniera facile e veloce senza che lo sviluppatore debba preoccuparsi della parte 'sporca' del codice ma 'soltanto' della sua parte logica, della suddivisione dei ruoli e della loro corretta applicazione.