Historique▲
Il y a quelques années, nous n'avions que ASP pour réaliser nos applications. Il fallait dès lors écrire toutes les méthodes pour gérer les utilisateurs au travers de l'application.
Ensuite, avec l'arrivée d'asp.net 1.x, cette gestion a été simplifiée grâce à l'arrivée du mode d'authentification « forms ». Malheureusement il restait pas mal de code à écrire…
Asp.net 2.0 amène toute une série de nouveautés concernant la gestion des utilisateurs. On y retrouve :
- des providers (la couche d'accès aux données en quelque sorte) ;
- des composants (la partie visuelle du membership) ;
- des API.
On retrouve aussi les différentes couches nécessaires à l'implémentation d'une gestion d'utilisateurs, ce qui nous permet de nous concentrer sur le cœur de l'application que nous réalisons.
Nous allons dès lors présenter chacune des couches.
Les « API Membership »▲
À quoi servent les API Membership? Elles permettent de :
- créer des utilisateurs,
- sauvegarder des informations dans des environnements différents ;
- authentifier des utilisateurs ;
- gérer des mots de passe.
Quel est l'intérêt d'utiliser ces API? Par définition il s'agit de faire l'interface entre les applications et les sources de données.
De plus, asp.net 2.0 est « prêt » à utiliser ces différentes API. Effectivement, tous les composants « Login », comme LoginName, Login, CreateUser… utilisent ces API.
Membership service▲
Sur ce schéma, on peut y voir plusieurs couches (de bas en haut) :
- sources de données ;
- providers ;
- API ;
- contrôles de login.
Sources de données
Il s'agit des bases de données, fichiers, Active Directory…
Providers
Chaque provider doit permettre d'accéder à une source de données en particulier. Il fournit les différentes méthodes pour écrire / lire dans cette source. Nous allons détailler les providers un peu plus loin dans cet article.
API
Les API sont des classes qui possèdent différentes méthodes qui permettent d'effectuer certaines actions. Ces méthodes s'appuient sur le provider en action.
Contrôles de login
Alors qu'il était souvent nécessaire de réaliser son propre contrôle pour authentifier les utilisateurs ou encore manipuler les informations s'y rapportant, asp.net 2.0 a amené toute une série de contrôles le permettant.
Classe MembershipProvider : les méthodes▲
- UpdateUser (Mise à jour des données d'un utilisateur)
- CreateUser (Création d'un utilisateur)
- DeleteUser (Suppression d'un utilisateur)
- ValidateUser (Validation de l'inscription d'un utilisateur suite à un clic dans un email)
- UnlockUser
- GetUserNameByEmail (Récupération du nom de l'utilisateur en connaissant son adresse mail)
- FindUsersByEmail/FindUsersByName (Récupération d'un objet « User » à partir d'une de ses informations)
- ResetPassword (Génération et enregistrement d'un nouveau mot de passe)
- ChangePassword (Mise à jour du mot de passe d'un utilisateur)
- …
Comme on peut le voir, chaque provider doit fournir toutes les méthodes pour manipuler toutes les informations concernant un utilisateur.
On retrouve également :
- CreateRole (Création d'un rôle) ;
- DeleteRole (Suppression d'un rôle) ;
- AddUserToRole (Ajout d'un rôle à un utilisateur).
Les dernières méthodes permettent de manipuler les rôles des utilisateurs. Pour cela il faut activer la gestion des rôles dans le Web.Config comme l'indique la ligne suivante :
<roleManager
enabled
=
“true” />
Pour les non-adeptes des modifications dans le Web.config, je vous rassure, il est possible d'utiliser le site de configuration intégré.
Pour y accéder, dans le menu Web Site, cliquez sur « asp.net website configuration ».
Revenons quelques instants à notre classe dérivée de MembershipProvider.
Après avoir ajouté une classe XmlMemberShipProvider, il faut la faire dériver de MemberShipProvider. Pour cela, il est nécessaire d'ajouter « : MemberShipProvider » après le nom de la classe.
Ensuite, il ne reste plus qu'à dire à Visual Studio d'implémenter toutes les méthodes de cette classe comme sur l'image suivante :
public
override
string
GetPassword
(
string
username,
string
answer)
{
// On ne gère pas la réponse
System.
IO.
StreamReader sr =
_
new
System.
IO.
StreamReader
(
HttpContext.
Current.
Server.
MapPath
(
"~/users.txt"
));
string
s =
sr.
ReadLine
(
);
sr.
Close
(
);
string
[]
str =
s.
Split
(
':'
);
if
(
str[
0
]
==
username)
return
str[
1
];
throw
new
Exception
(
"Utilisateur inconnu"
);
}
public
override
MembershipUser CreateUser
(
string
username,
string
password,
string
email,
_
string
passwordQuestion,
string
passwordAnswer,
bool
isApproved,
object
providerUserKey,
_
out
MembershipCreateStatus status)
{
System.
IO.
StreamWriter sw =
_
new
System.
IO.
StreamWriter
(
HttpContext.
Current.
Server.
MapPath
(
"~/users.txt"
));
sw.
WriteLine
(
username +
":"
+
password +
":"
+
email);
sw.
Flush
(
);
sw.
Close
(
);
status =
MembershipCreateStatus.
Success;
return
new
MembershipUser
(
"TextMemberShipProvider"
,
username,
providerUserKey,
email,
_
passwordQuestion,
""
,
true
,
false
,
DateTime.
Now,
DateTime.
Now,
DateTime.
Now,
_
DateTime.
Now,
DateTime.
Now);
}
public
override
bool
EnablePasswordRetrieval
{
get
{
return
true
;
}
}
public
override
bool
ValidateUser
(
string
username,
string
password)
{
System.
IO.
StreamReader sr =
_
new
System.
IO.
StreamReader
(
HttpContext.
Current.
Server.
MapPath
(
"~/users.txt"
));
string
s =
sr.
ReadLine
(
);
string
[]
str =
s.
Split
(
':'
);
sr.
Close
(
);
if
(
str[
0
]
==
username &&
str[
1
]
==
password)
return
true
;
return
false
;
}
Profiling▲
Déclaration dans le web.config▲
Chaque application a des besoins différents concernant les informations à garder à propos du profil d'un utilisateur. Asp.net 2.0 a ainsi amené la possibilité de définir cela dans le fichier de configuration de l'application (Web.Config).
L'exemple de déclaration dans le Web.Config qui suit permet d'indiquer qu'un « Profile » doit avoir les propriétés suivantes :
- Theme (thème à utiliser) ;
- Birthday (date d'anniversaire) ;
- LoginCount (nombre d'authentifications).
<profile>
<properties>
<add
name
=
"Theme"
/>
<add
name
=
"Birthday"
type
=
"System.DateTime"
/>
<add
name
=
"LoginCount"
type
=
"System.Int32"
defaultValue
=
"0"
/>
</properties>
</profile>
Utilisation dans le code▲
Après une simple compilation, la classe statique Profile est « mise à jour » et possède les différentes propriétés que l'on vient de définir dans le web.config.
On peut dès lors l'utiliser comme n'importe quelle autre propriété en utilisant l'Intellisense. On notera par ailleurs que les propriétés sont typées, ce qui signifie qu'à Birthday qui est de type DateTime, il n'est pas possible de passer un int par exemple.
string
theme =
Profile.
Theme;
dateTime anniversaire =
Profile.
Birthday;
&
#8230
;
Profile.
Theme =
"test“;
Membership Provider▲
Tous les providers dérivent de la classe abstraite MembershipProvider
Étant donné que la classe est dérivée,
TextMembershipProvider :
MembershipProvider
Définition dans le web.config▲
De plus en plus, on tend à réaliser des applications qui demandent peu de développement en favorisant la configuration. On ne s'en plaindra pas puisqu'une application peut être adaptée très rapidement pour passer d'un provider (dans notre cas) à l'autre sans aucune recompilation.
Étant donné que Membership est géré par le framework, on retrouve un tag particulier dans le Web.Config. Il s'agit de « membership » que l'on trouve en tant que fils du nœud « system.web ».
Dans la section membership, nous retrouvons les différents providers sous la forme de
<add
name
=
“TextMembershipProvider
" type=“TextMembershipProvider"
enablePasswordRetrieval
=
“true
" enablePasswordReset=“true“
… />
dont le contenu est simple à comprendre. Effectivement il s'agit du nom donné au Provider, la classe à utiliser pour réaliser les différentes opérations ainsi que divers paramètres permettant de spécifier quelles fonctionnalités sont fournies ou non par le provider.
Voici un exemple en utilisant le provider que nous venons de créer.
<system.web>
...
<membership
defaultProvider
=
“TextMembershipProvider
">
<providers>
<add name=“TextMembershipProvider"
type
=
“TextMembershipProvider
"
enablePasswordRetrieval=“true"
enablePasswordReset
=
“true“ … />
</providers>
</membership>
...
</system.web>
On notera également la présence de l'attribut « defaultProvider » qui permet de spécifier qu'il s'agit d'utiliser ce provider par défaut.
Conclusion▲
En 30 minutes nous avons réalisé un provider pour le membership. Nous avons également vu que le passage d'un provider à un autre est très simple à réaliser.
Pensez-y lors de la réalisation de vos applications. Modifier une valeur dans un Web.Config coûte moins cher à un client et amène moins de risques que de redévelopper une application complète. Ceci est évidemment valable pour tous les domaines de l'application.