Logo Spiria

Créer votre propre alternative à SqlMembershipProvider (.NET)

2 février 2016.
Vous désirez utiliser le système d’authentification d’appartenance d’ASP.NET SQL, mais les règles sur l’accès aux données vous semblent trop contraignantes? Pourquoi ne pas créer votre propre fournisseur pour remplacer le SqlMembershipProvider par défaut, et ce, peu importe la manière dont vous accédez aux données sélectionnées.

Vous désirez utiliser le système d’authentification d’appartenance d’ASP.NET SQL, mais les règles sur l’accès aux données vous semblent trop contraignantes? Pourquoi ne pas créer votre propre fournisseur pour remplacer le SqlMembershipProvider par défaut, et ce, peu importe la manière dont vous accédez aux données sélectionnées.

À titre d’exemple : vous êtes dans l’obligation d’utiliser une plateforme en ligne ou la base de données d’utilisateurs existe déjà. La solution suivante vous permettra de gérer de telles situations sans avoir recours à SqlMembershipProvider.

Étape 1 : repérer les données à gérer

En tenant pour acquis qu’il s’agit du contrat de données que fournit un service web et en considérant le modèle de données suivant :

    {
        public long UserId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Email { get; set; }
        public string Password { get; set; }
        public string Address { get; set; }
        public string City { get; set; }
        public string ZipCode { get; set; }
        public string Country { get; set; }
        public bool IsActive { get; set; }
        public DateTime CreationDate { get; set; }
        public DateTime LastLoginDate { get; set; }
    }

En considérant également le service d’accès aux données, dont voici l’interface :

    public class AuthenticationService : IDisposable
    {
        public bool UserExists(string email, string password)
        {
            //implementation here
        }

        public User GetUser(string username)
        {
            //implementation here
        }

        public User GetUser(long userId)
        {
            //implementation here
        }

        public bool UpdateUser(User user)
        {
            //implementation here
        }

        public void Dispose()
        {
            //implementation here
        }
    }

Étape 2 : créer un MembershipUser sur mesure, en s’inspirant de l’original

As can be seen, this class has the contract "User" as a property.

    public class CustomMemberShipUser : MembershipUser
    {
        private readonly User _userData;

        public User UserData
        {
            get { return _userData; }
        }

        
        /// 
/// Constructor of MemberShip derived class ///
public CustomMemberShipUser(string providername, User userData) : base(providername, userData.Email, userData.UserId, userData.Email, string.Empty, string.Empty, true, !userData.IsActive, userData.CreationDate, userData.LastLoginDate, DateTime.Now, DateTime.Now, DateTime.Now) { this._userData = userData; } }

Remarquez que vous devrez importer l’assemblage « System.Web.Security ».

J’ai utilisé les données du contrat « User » pour remplir les champs appropriés dans la classe de base.

J’ai également décidé que le nom d’utilisateur serait le courriel « !userData.IsActive », rempli dans la propriété « isLockedOut » de la classe de base.

Étape 3 : créer un MembershipProvider sur mesure, en s’inspirant de l’original

Remarquez que vous devez implémenter toutes les méthodes. Sinon, vous devrez créer une méthode « override » et ajouter la ligne « throw new NotImplementedException(); ».

    public class CustomMemberShipProvider : MembershipProvider
    {
        public override bool ValidateUser(string username, string password)
        {
            using (var service = new AuthenticationService())
            {
                return service.UserExists(username, password);
            }
        }

        public override MembershipUser GetUser(string username, bool userIsOnline)
        {
            using (var service = new AuthenticationService())
            {
                var user = service.GetUser(username);

                if (null != user)
                    return new CustomMemberShipUser(Membership.Provider.ApplicationName, user);

                return null;
            }
        }

        public override void UpdateUser(MembershipUser userToUpdate)
        {
            var user = (CustomMemberShipUser) userToUpdate;
            using (var service = new AuthenticationService())
            {
                var result = service.UpdateUser(user.UserData);
                if (!result)
                    throw new Exception("User has not been updated");
            }

        }

        public override string ApplicationName
        {
            get { return "MyAppMemberShip"; }
            set { throw new NotImplementedException(); }
        }

        public override bool ChangePassword(string username, string oldPassword, string newPassword)
        {
            throw new NotImplementedException();
        }

        ///
        /// 
        /// all overrrided methods
        /// 
        /// 

    }

Étape 4 : définissez ce MembershipProvider comme fournisseur par défaut dans votre web.config 

Remarquez que « Membership.CustomMemberShipProvider, MemberShip » est mon assemblage sur mesure. 

<system.web>
    <compilation debug="true" targetframework="4.5">
    <httpruntime targetframework="4.5">
    <authentication mode="Forms">
      <forms loginurl="~/Home/DoLogin" timeout="2880">
    </forms></authentication>
    <strong><membership defaultprovider="MyAppMemberShip">
      <providers>
        <clear>
        <add name="MyAppMemberShip" type="MemberShip.CustomMemberShipProvider, MemberShip">
      </add></clear></providers>
    </membership></strong>
  </httpruntime></compilation></system.web>

Étape 5 : ajouter le mode d’authentification (incluant l’url de la page) à votre web.config, en respectant la syntaxe classique de SqlMembershipProvider

<system.web>
    <compilation debug="true" targetframework="4.5">
    <httpruntime targetframework="4.5">
    <strong><authentication mode="Forms">
      <forms loginurl="~/Home/DoLogin">
    </forms></authentication></strong>
    <membership defaultprovider="MyAppMemberShip">
      <providers>
        <clear>
        <add name="MyAppMemberShip" type="MemberShip.CustomMemberShipProvider, MemberShip">
      </add></clear></providers>
    </membership>
  </httpruntime></compilation></system.web>

Étape 6 : tester votre implémentation !

N’oubliez pas d’utiliser la classe  « FormsAuthentification » de manière à créer le cookie « .ASPXAUTH ». Il est nécessaire pour que MembershipProvider puisse identifier l’utilisateur et gérer la méthode de déconnexion. 

    public class HomeController : Controller
    {
        public ActionResult DoLogin()
        {
            if (Membership.ValidateUser("myemail@example.com", "xxxxx"))
            {
                FormsAuthentication.SetAuthCookie("myemail@example.com", true);
                return Content("login success");
            }
            return Content("login error");
        }

        public ActionResult Index()
        {
            if (User.Identity.IsAuthenticated)
            {
                var user = (CustomMemberShipUser)Membership.GetUser();
                return Content("User connected!");
            }

            return RedirectToAction("DoLogin");
        }

        public void SignOut()
        {
            FormsAuthentication.SignOut();
        }

    }

 

Voici le résultat, suite à l’exécution en démo : 

Rien de plus simple, n’est-ce pas?  ;)