Переопределение провайдера членства

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core

Последнее обновление: 31.10.2015

В прошлом разделе мы создали базовую инфраструктуру для собственных провайдеров членства и ролей, а теперь перейдем непосредственно к переопределению провайдера членства. Сначала добавим в проект папку Providers, где будут находиться провайдеры членства и ролей. Потом добавим в эту папку новый класс - назовем его CustomMembershipProvider. Он будет иметь следующее определение:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.Helpers;
using System.Security.Cryptography;
using System.Web.WebPages;
using Microsoft.Internal.Web.Utils;
using CustomAuthorization.Models;

namespace CustomAuthorization.Providers
{
    public class CustomMembershipProvider : MembershipProvider
    {
        public override bool ValidateUser(string username, string password)
        {
            bool isValid = false;

            using (UserContext _db = new UserContext())
            {
                User user = _db.Users.FirstOrDefault(u => u.Email == username);

                if (user != null &&  Crypto.VerifyHashedPassword(user.Password,password))
                {
					isValid = true;
                }
				return isValid;
            }
        }
        
        public MembershipUser CreateUser(string email, string password)
        {
            MembershipUser membershipUser = GetUser(email, false);

            if (membershipUser == null)
            {
                try
                {
                    using (UserContext _db = new UserContext())
                    {
                        User user = new User();
                        user.Email = email;
                        user.Password = Crypto.HashPassword(password);
                        user.CreationDate = DateTime.Now;

                        if(_db.Roles.Find(2)!=null)
                        {
                            user.RoleId = 2;
                        }

                        _db.Users.Add(user);
                        _db.SaveChanges();
                        membershipUser=GetUser(email, false);
                        return membershipUser;
                    }
                }
                catch
                {
                    return null;
                }
            }
            return null;
        }

        public override MembershipUser GetUser(string email, bool userIsOnline)
        {
            try
            {
                using (UserContext _db = new UserContext())
                {
                    var users = from u in _db.Users
                                where u.Email == email
                                select u;
                    if (users.Count() > 0)
                    {
                        User user = users.First();
                        MembershipUser memberUser = new MembershipUser("MyMembershipProvider", user.Email, null, null, null, null,
                            false, false, user.CreationDate, DateTime.MinValue, DateTime.MinValue, DateTime.MinValue, DateTime.MinValue);
                        return memberUser;
                    }
                }
            }
            catch
            {
                return null;
            }
            return null;
        }
		
        public override string ApplicationName
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

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

        public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
        {
            throw new NotImplementedException();
        }

        public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
        {
            throw new NotImplementedException();
        }

        public override bool DeleteUser(string username, bool deleteAllRelatedData)
        {
            throw new NotImplementedException();
        }

        public override bool EnablePasswordReset
        {
            get { throw new NotImplementedException(); }
        }
        public override bool EnablePasswordRetrieval
        {
            get { throw new NotImplementedException(); }
        }
        public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            throw new NotImplementedException();
        }
        public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            throw new NotImplementedException();
        }
        public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
        {
            throw new NotImplementedException();
        }
        public override int GetNumberOfUsersOnline()
        {
            throw new NotImplementedException();
        }
        public override string GetPassword(string username, string answer)
        {
            throw new NotImplementedException();
        }
        public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
        {
            throw new NotImplementedException();
        }
        public override string GetUserNameByEmail(string email)
        {
            throw new NotImplementedException();
        }
        public override int MaxInvalidPasswordAttempts
        {
            get { throw new NotImplementedException(); }
        }
        public override int MinRequiredNonAlphanumericCharacters
        {
            get { throw new NotImplementedException(); }
        }
        public override int MinRequiredPasswordLength
        {
            get { throw new NotImplementedException(); }
        }
        public override int PasswordAttemptWindow
        {
            get { throw new NotImplementedException(); }
        }
        public override MembershipPasswordFormat PasswordFormat
        {
            get { throw new NotImplementedException(); }
        }
        public override string PasswordStrengthRegularExpression
        {
            get { throw new NotImplementedException(); }
        }
        public override bool RequiresQuestionAndAnswer
        {
            get { throw new NotImplementedException(); }
        }
        public override bool RequiresUniqueEmail
        {
            get { throw new NotImplementedException(); }
        }
        public override string ResetPassword(string username, string answer)
        {
            throw new NotImplementedException();
        }
        public override bool UnlockUser(string userName)
        {
            throw new NotImplementedException();
        }
        public override void UpdateUser(MembershipUser user)
        {
            throw new NotImplementedException();
        }
    }    
}

Теперь разберем класс провайдера. Во-первых, чтобы реализовать провайдер членства, надо унаследовать его от абстрактного класса MembershipProvider и переопределить его методы. В нашем провайдере в качестве примера мы переопределим всего два метода. Остальные останутся нереализованными.

(Поскольку приложение использует класс шифрования Crypto, то необходимо добавить в проект сборку System.Web.Helpers.dll)

Первый переопределенный метод - ValidateUser. Он срабатывает при логине пользователя в системе. В нем мы пытаемся найти пользователя по полученным в качестве параметров логине и паролю с помощью контекста UserContext. Если пользователь найден, то он прошел валидацию.

Второй переопределенный метод - GetUser. В нем мы похожим образом пытаемся найти пользователя по введенному логину, только теперь мы возвращаем объект MebershipUser, определяющий пользователя членства. При желании можно определить свой класс пользователя членства, но для данного примера сойдет и стандартный. В качестве параметров мы передаем ему свойства пользователя в конструкторе:

MembershipUser memberUser = new MembershipUser("MyMembershipProvider", user.Email, null, null, null, null,
                    false, false, user.CreationDate, DateTime.MinValue, DateTime.MinValue, DateTime.MinValue, DateTime.MinValue);

Тут нас интересуют только пара-тройка параметров - имя провайдера членства, логин (он же email) и дата создания. А параметры со значениями null и DateTime.MinValue в данном случае нам не важны.

Перейдем к третьему определенному в классе методу - CreateUser. Он создает при регистрации нового пользователя.

Мы могли бы и переопределить унаследованный метод CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status), передав данные пользователя в виде параметров. Но в данном случае для большей простоты и разнообразия воспользуемся другим способом - создадим свою перегрузку этого метода.

В этом методе новый пользователь через UserContext просто добавляется в БД. Здесь же мы присваиваем роль пользователю. На выходе получаем с помощью ранее переопределенного метода GetUser объект MembershipUser.

Теперь изменим файл web.config, чтобы наше приложение работало с нашим провайдером членства. Во-первых, уберем или закомментируем в этом файле определения других провайдеров:

	<profile defaultProvider="DefaultProfileProvider">
      <providers>
        <add name="DefaultProfileProvider" type="System.Web.Providers.DefaultProfileProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" applicationName="/" />
      </providers>
    </profile>
    <membership defaultProvider="DefaultMembershipProvider">
      <providers>
        <add name="DefaultMembershipProvider" type="System.Web.Providers.DefaultMembershipProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
      </providers>
    </membership>
    <roleManager defaultProvider="DefaultRoleProvider">
      <providers>
        <add name="DefaultRoleProvider" type="System.Web.Providers.DefaultRoleProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" applicationName="/" />
      </providers>
    </roleManager>
    <sessionState mode="InProc" customProvider="DefaultSessionProvider">
      <providers>
        <add name="DefaultSessionProvider" type="System.Web.Providers.DefaultSessionStateProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" />
      </providers>
    </sessionState>

И вместо них добавим определение нашего провайдера:

	<membership defaultProvider="MyMembershipProvider">
      <providers>
        <clear/>
        <add name="MyMembershipProvider" type="CustomAuthorization.Providers.CustomMembershipProvider" />
      </providers>
    </membership>

И финальная часть - создание контроллера. Добавим в проект в папку Controllers контроллер AccountCotroller. Он будет иметь следующий код:

using System;
using System.Web;
using System.Web.Mvc;
using CustomAuthorization.Models;
using System.Web.Security;
using CustomAuthorization.Providers;

namespace CustomAuthorization.Controllers
{
    [AllowAnonymous]
    public class AccountController : Controller
    {
        public ActionResult Login()
        {
            return View();
        }
        [HttpPost]
        public ActionResult Login(LogOnModel model, string returnUrl)
        {
            if (ModelState.IsValid)
            {
                if (Membership.ValidateUser(model.UserName, model.Password))
                {
                    FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
                    if (Url.IsLocalUrl(returnUrl))
                    {
                        return Redirect(returnUrl);
                    }
                    else
                    {
                        return RedirectToAction("Index", "Home");
                    }
                }
                else
                {
                    ModelState.AddModelError("", "Неправильный пароль или логин");
                }
            }
            return View(model);
        }
        public ActionResult LogOff()
        {
            FormsAuthentication.SignOut();

            return RedirectToAction("Login", "Account");
        }

        public ActionResult Register()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Register(RegisterModel model)
        {
            if (ModelState.IsValid)
            {
                MembershipUser membershipUser = ((CustomMembershipProvider)Membership.Provider).CreateUser(model.Email, model.Password);

                if (membershipUser != null)
                {
                    FormsAuthentication.SetAuthCookie(model.Email, false);
                    return RedirectToAction("Index", "Home");
                }
                else
                {
                    ModelState.AddModelError("", "Ошибка при регистрации");
                }
            }
            return View(model);
        }
    }
}

Метод Login имеет стандартную реализацию, только теперь при вызове метода Membership.ValidateUser будет использоваться соответствующий метод нашего провайдера.

В методе Register мы используем код MembershipUser membershipUser = ((CustomMembershipProvider)Membership.Provider).CreateUser(model.Email, model.Password), чтобы получить пользователя членства. Так как здесь использовался не переопределенный метод CreateUser, а его перегрузка, то нам необходимо привести используемый провайдер к типу нашего провайдера: (CustomMembershipProvider)Membership.Provider

Таким образом, после регистрации данные пользователя будут попадать в таблицу Users, определенную в нашей БД, и мы сможем его затем использовать при авторизации и аутентификации.

Если нам при регистрации надо передавать дополнительные параметры в бд, то мы можем просто создать другую перегрузку для метода CreateUser, добавив нужные параметры.

А теперь, используя имеющиеся модели и бд, создадим собственный провайдер ролей.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850