Introduction
Dans cet article, je vais vous expliquer, dans un premier temps, comment réaliser un module d'authentification ASP.NET à l'aide de la technologie AJAX (Asynchronous Javascript And Xml). Dans un deuxième temps, nous verrons comment personnaliser l'authentification, c'est-à-dire comment créer notre propre service d'authentification asynchrone.
Avant cela, commençons par quelques rappels élémentaires sur la technologie AJAX.
Rappels : AJAX, mais qu'est-ce que c'est ?
AJAX est un terme qui a été introduit en 2005 pour représenter une technologie permettant de charger des données sur nos pages web de manière asynchrone, c'est-à-dire que seule une partie de la page souhaitée est rafraîchie. AJAX signifie Asynchronous Javascript And Xml. En effet, les échanges asynchrones avec le serveur reposent sur le langage XML.
L'avantage de cette technologie est de ne rafraîchir que le nécessaire pour améliorer l'expérience utilisateur. Cette technologie connaît son apogée avec l'arrivée du Web 2.0. Elle est totalement supportée par la dernière version d'ASP.NET : ASP.NET 3.5.
Création du formulaire d'authentification
Commençons par créer un nouveau projet de type Site Web ASP.NET (.NET Framework 3.5) dans Visual Studio. Nous allons créer notre formulaire sur la page Default.aspx :
<body>
<form id="form_login" runat="server">
<div id="anonymousTemplate">
<table>
<tr>
<td colspan="2" style="text-align:center;">Authentication module</td>
</tr>
<tr>
<td>Username</td>
<td>
<input type="text" id="tbUsername" />
</td>
</tr>
<tr>
<td>Password</td>
<td>
<input type="password" id="tbPassword" />
</td>
</tr>
<tr>
<td colspan="2">
<input type="checkbox" id="chkRememberMe" checked="checked" />
Remember me next time.
</td>
</tr>
<tr>
<td colspan="2" style="text-align:center">
<input type="button" value="Log In" id="btnLogin" />
</td>
</tr>
</table>
</div>
<div id="loggedInTemplate" style="display:none;">
<span id="userInfomation"></span>
<a href="" title="Logout">Logout</a>
</div>
</form>
</body>
Remarquez la présence de deux balises « div », anonymousTemplate et loggedInTemplate. C'est ici volontairement que je n'utilise pas le contrôle ASP.NET « LoginView ».
Vous devriez alors obtenir quelque chose comme ceci :
Création du code JavaScript associé au login :
Nous allons maintenant ajouter un fichier de type AJAX Client Library à notre projet. J'ai choisi d'appeler ce fichier « Authentication.js ». C'est dans celui-ci que nous allons écrire notre code JavaScript permettant de réaliser l'authentification :
Remarquez la directive ajoutant une référence vers le fichier « MicrosoftAjax.js »contenant les classes et fonctions JavaScript que nous allons utiliser :
/// <reference name="MicrosoftAjax.js"/>
Voyons un aperçu des outils proposés par Microsoft pour la gestion des utilisateurs en AJAX. Tous ces outils reposent sur des services web, que nous chargerons via le fichier de configuration un peu plus loin dans cet article.
Sys.Services.AuthenticationService
Cette classe fournit un proxy pour l'authentification ASP.NET en AJAX. Les deux principales méthodes qui vont nous intéresser sont :
- login : elle prend en paramètre le nom de l'utilisateur à authentifier, son mot de passe, un booléen indiquant si le cookie d'authentification doit être persistant, l'url de redirection, la fonction à appeler en cas de succès, celle à appeler en cas d'échec et des informations sur l'utilisateur.
- logout : elle prend en paramètre l'url de redirection, la fonction à appeler en cas de succès, celle à appeler en cas d'échec et des informations sur l'utilisateur.
Elle nous fournit aussi une propriété nous permettant de savoir si l'utilisateur est authentifié ou pas : isLoggedIn.
Sys.Services.ProfileService
Cette classe nous fournit un proxy pour manipuler les profils utilisateurs. Deux méthodes sont intéressantes :
- load : cette méthode est à appeler avant de récupérer un champ de profil. Elle prend en paramètre un tableau représentant le nom des propriétés à charger, une fonction à appeler en cas de succès, une en cas d'échec et des informations sur le contexte utilisateur.
- save : Elle prend les mêmes paramètres que load, mais permet de sauvegarder le profil utilisateur.
On retrouve aussi une propriété intéressante : properties, qui va nous permettre de récupérer les champs du profile de notre utilisateur (conformes à ceux définis dans le fichier de configuration de notre site web).
Nous allons à présent écrire le code qui sera exécuté lors du clic sur le bouton « Log In » dans le fichier Authentication.js.
Méthode d'authentification JavaScript
/// <reference name="MicrosoftAjax.js"/>
function doLogin() {
var authService = Sys.Services.AuthenticationService;
if (!authService.get_isLoggedIn()) {
var username = $get("tbUsername").value;
var password = $get("tbPassword").value;
var rememberMe = $get("chkRememberMe").checked;
authService.login(username, password, rememberMe, null, null, loginCompleteCallBack, null, null);
}
}
Ici, il faut remarquer l'appel de la fonction login du service d'authentification.Vous pourrez remarquer au passage que tous les arguments ne sont pas obligatoires, ceux-ci acceptant la valeur « null ». Je souhaite souligner aussi l'utilisation de la directive « $get » qui est un raccourci d'écriture pour la fonction « document.getElementById ».
function loginCompleteCallBack(result, context, methodName) {
if (result)//login succeed
{
$get("anonymousTemplate").style.display = "none";
$get("loggedInTemplate").style.display = "";
}
else {
window.alert('Login fails, please check your credentials.');
}
}
Nous allons lancer l'appel de la fonction « doLogin » sur le clic du bouton « Log In » :
<input type="button" value="Log In" id="btnLogin" onclick="javascript:doLogin();" />
A ce stade, si nous exécutons le site web, nous aurons des erreurs sur la page, en effet il faut que nous référencions le script JavaScript afin que la fonction doLogin soit visible. Pour cela, nous allons rajouter un script manager à notre page. Le ScriptManager est un composant ASP.NET 3.5 permettant de gérer les scripts JavaScript sur notre page ainsi que de modifier le comportement de certains services tels que le service d'authentification AJAX. Nous aborderons ceci en fin d'article. La balise ScriptReference nous permet de référencer le fichier de code JavaScript que nous avons crée :
<form id="form_login" runat="server">
<asp:ScriptManager ID="MyScriptManager" runat="server">
<Scripts>
<asp:ScriptReference Path="~/js/Authentication.js" />
</Scripts>
</asp:ScriptManager>
A présent nous devons configurer notre site web pour utiliser l'authentification par formulaire, et surtout faire en sorte que les services web d'authentification AJAX soient chargés.
Configuration de l'application web
Configuration de l'authentification par formulaire
Commencez par cliquer sur l'icône représentant une planète et un marteau dans l'explorateur de solution Visual Studio :
Le site web de configuration de votre application web s'ouvre alors. Cliquez sur le lien « Security » :
Puis choisissez « Select authentication type » :
Et enfin « From the Internet » :
Ceci aura pour but d'activer l'authentification par formulaire pour votre application web. De plus, cela crée la base de données permettant le stockage des utilisateurs, ainsi que toutes les tables d'authentification ASP.NET :
Nous devons maintenant ajouter des directives au fichier de configuration pour travailler avec l'authentification ASP.NET :
- La chaîne de connexion vers la base précédemment crée :
<connectionStrings>
<add name="ConnectionString" providerName="System.Data.SqlClient"
connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=C:\Projects\AjaxAuthentication\App_Data\ASPNETDB.MDF;Integrated Security=True;User Instance=True"/>
</connectionStrings>
<profile defaultProvider="SqlProfileProvider">
<providers>
<clear/>
<add name="SqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ConnectionString" />
</providers>
<properties>
<add name="Welcome" type="System.String" defaultValue="Hello World"/>
</properties>
</profile>
- Le fournisseur d'authentification :
<membership defaultProvider="SqlMembershipProvider">
<providers>
<clear/>
<add name="SqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="ConnectionString" />
</providers>
</membership>
et travailler avec les services AJAX :
<system.web.extensions>
<scripting>
<webServices>
<authenticationService enabled="true" />
<profileService enabled="true" readAccessProperties="Welcome"/>
</webServices>
</scripting>
</system.web.extensions>
Nous chargeons ici deux services web : le service d'authentification et le service de gestion de profil. Remarquez la directive « readAccessProperties » qui nous permet de préciser quels champs du profil doivent être chargés de manière asynchrone. Une directive similaire existe pour l'écriture asynchrone de données de profil : « writeAccessProperties ».
Vous pouvez maintenant créer un utilisateur via l'interface web précédente :
Vous pouvez désormais tester votre page web et vous authentifier avec votre utilisateur fraîchement créé, ainsi qu'avec des identifiants ne fonctionnant pas pour constater l'erreur :
Vérifications de l'état authentifié ou non au chargement de la page et méthode logout
Maintenant que nous sommes capables d'authentifier un utilisateur, nous devons pouvoir afficher ou non le formulaire au chargement de la page, et surtout lui permettre de se déconnecter en cliquant sur « Logout ».
Revenons dans le fichier Authentication.js est ajoutons la méthode pageLoad suivante :
function pageLoad() {
var authService = Sys.Services.AuthenticationService;
if (authService.get_isLoggedIn()) {
$get("anonymousTemplate").style.display = "none";
$get("loggedInTemplate").style.display = "";
}
else {
$get("anonymousTemplate").style.display = "";
$get("loggedInTemplate").style.display = "none";
}
}
Ainsi le template varie que l'utilisateur soit authentifié ou non. Il nous suffit de lier cette fonction au chargement de notre page web :
<body onload="javascript:pageLoad();">
Nous pouvons maintenant créer la fonction Logout et la lier au lien « Logout » :
function Logout() {
var authService = Sys.Services.AuthenticationService;
authService.logout(null, null, null, null);
$get("anonymousTemplate").style.display = "";
$get("loggedInTemplate").style.display = "none";
}
<a href="javascript:Logout();" title="Logout">Logout</a>
Voyons à présent comment récupérer les données du profil utilisateur.
Récupération du profil utilisateur
Pour récupérer les données du profile, il faut avant tout demander leur chargement par l'appel de la fonction load suscitée. Pour cela, lorsque le login réussi, nous allons rajouter le code suivant :
var profileService = Sys.Services.ProfileService;
profileService.load(null, loadCompleteCallback,null,null);
Ainsi que la fonction loadCompleteCallback appelée lorsque le profil utilisateur est chargé :
function loadCompleteCallback(numProperties, userContext, methodName)
{
var profileService = Sys.Services.ProfileService;
var userInformation = $get("userInfomation");
userInformation.innerText = profileService.properties.Welcome;
}
Nous affichons tout simplement les informations récupérées, ici la valeur du champ « Welcome » (Hello World, par défaut) :
Personnalisation du service d'authentification ASP.NET AJAX
Comme nous l'avons vu précédemment, l'authentification ASP.NET asynchrone repose sur l'appel de services web. Dans cette section, nous allons voir comment créer notre propre service d'authentification. Pour cela, nous devons ajouter un nouvel item au projet, de type Service Web :
Avant d'écrire nos fonctions d'authentification, nous devons rendre le service web utilisable par AJAX, et ce en décommentant la ligne précédent le prototype de la classe de notre service web :
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
// [System.Web.Script.Services.ScriptService]
public class CustomAuthenticationService : System.Web.Services.WebService {
devient:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
[System.Web.Script.Services.ScriptService]
public class CustomAuthenticationService : System.Web.Services.WebService {
C'est l'attribut ScriptService qui va rendre notre service web invoquable depuis du code JavaScript.
Nous devons à présent définir deux méthodes web Login et Logout permettant l'authentification :
[WebMethod]
public bool Login(string userName, string password, bool createPersistentCookie)
{
if(Membership.ValidateUser(userName,password))
{
//code personnalisé ici
FormsAuthentication.SetAuthCookie(userName,createPersistentCookie);
return true;
}
return false;
}
[WebMethod]
public void Logout()
{
//code personnalisé ici
FormsAuthentication.SignOut();
}
Le service web est désormais terminé. Il ne nous reste plus qu'à préciser au service d'authentification que nous souhaitons utiliser le service web personnalisé ci-dessus créé. Pour cela, nous allons utiliser une directive du ScriptManager : AuthenticationService
<asp:ScriptManager ID="MyScriptManager" runat="server">
<Scripts>
<asp:ScriptReference Path="~/js/Authentication.js" />
</Scripts>
<AuthenticationService Path="~/CustomAuthenticationService.asmx" />
</asp:ScriptManager>
L'authentification AJAX personalisée est maintenant prête à l'emploi, il ne vous reste qu'à tester ! (et ça marche :])
J'espère que cet article permettra à la plupart d'entre vous de comprendre les bases de l'authentification ASP.NET AJAX et ce, afin d'améliorer l'expérience utilisateur de vos visiteurs !
A bientôt
Sources du projet : AjaxAuthentication.zip (8,36 mb)