Создание провайдера ролей

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

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

Универсальные провайдеры предоставляют уже готовый функционал авторизации. Но в то же время эти провайдеры обладают достаточной гибкостью - в частности мы можем их переопределить по своему усмотрению. При этом нам необязательно переопределять и использовать все четыре провайдера. Что довольно удобно, особенно в ситуации, когда нам не нужны все навороты ASP.NET Identity, а требуется построить очень простенькую систему авторизации.

Итак, создадим свой провайдер ролей. Для этого вначале создадим новый проект и добавим в него через NuGet Entity Framework.

Первым делом определим модели, которые будут описывать учетные записи. Это у нас будут модели пользователей и ролей, а также контекст данных для доступа к ним. Поэтому добавим в папку Models следующие классы:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;

namespace CustomRoleProviderApp.Models
{
    public class UserContext : DbContext
    {
		public UserContext() : base("DefaultConnection")
        { }
        public DbSet<User> Users { get; set; }
        public DbSet<Role> Roles { get; set; }
    }

    public class User
    {
        public int Id { get; set; }
        public string Email { get; set; }
        public string Password { get; set; }
        public int RoleId { get; set; }
        public Role Role { get; set; }
    }

    public class Role
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
	public class UserDbInitializer : DropCreateDatabaseAlways<UserContext>
    {
        protected override void Seed(UserContext db)
        {
			Role admin = new Role { Name = "admin" };
			Role user = new Role { Name = "user" };
            db.Roles.Add(admin);
            db.Roles.Add(user);
            db.Users.Add(new User 
            { 
                Email="somemail@gmail.com", 
                Password="123456",
                Role = admin
            });
            base.Seed(db);
        }
    }
}

Здесь определен класс пользователя и класс ролей. Класс пользователя содержит ссылку на выполняемую роль в системе. И также определен контекст UserContext, через который мы будем получать данные из БД. Контекст данных связывается с подключение к бд, которое определено в файле web.config. При желании можно определить любое другое подключение.

Кроме того, чтобы инициализировать базу данных начальными данными, через класс инициализатора UserDbInitializer мы добавляем пару ролей и одного пользователя в базу данных. И чтобы инициализатор сработал, добавим его вызов в файл global.asax:

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        Database.SetInitializer(new UserDbInitializer());
        //............................................
    }
}

Теперь определим сам провайдер ролей. Для этого сначала добавим в проект папку Providers и затем в него добавим новый класс CustomRoleProvider:

using System;
using System.Linq;
using System.Web.Security;
using CustomRoleProviderApp.Models;
using System.Data.Entity;

namespace CustomRoleProviderApp.Providers
{
    public class CustomRoleProvider : RoleProvider
    {
        public override string[] GetRolesForUser(string username)
        {
            string[] roles = new string[] { };
            using (UserContext db = new UserContext())
            {
                // Получаем пользователя
                User user = db.Users.Include(u=>u.Role).FirstOrDefault(u => u.Email == username);
                if (user != null && user.Role!=null)
                {
                    // получаем роль
                    roles = new string[] { user.Role.Name };
                }
                return roles;
            }
        }
        public override void CreateRole(string roleName)
        {
            throw new NotImplementedException();
        }
        public override bool IsUserInRole(string username, string roleName)
        {
            using (UserContext db = new UserContext())
            {
                // Получаем пользователя
                User user = db.Users.Include(u=>u.Role).FirstOrDefault(u => u.Email == username);

                if (user!=null && user.Role!=null && user.Role.Name == roleName)
                    return true;
                else
                    return false;
            }
        }
        public override void AddUsersToRoles(string[] usernames, string[] roleNames)
        {
            throw new NotImplementedException();
        }

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

        public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
        {
            throw new NotImplementedException();
        }

        public override string[] FindUsersInRole(string roleName, string usernameToMatch)
        {
            throw new NotImplementedException();
        }

        public override string[] GetAllRoles()
        {
            throw new NotImplementedException();
        }

        public override string[] GetUsersInRole(string roleName)
        {
            throw new NotImplementedException();
        }

        public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
        {
            throw new NotImplementedException();
        }

        public override bool RoleExists(string roleName)
        {
            throw new NotImplementedException();
        }
    }
}

В целях демонстрации переопределено три метода. Первый из них - GetRolesForUser позволяет получать набор ролей для определенного пользователя. Второй метод - - IsUserInRole - определяет, выполняет ли пользователь определенную роль в системе.

Чтобы использовать провайдер ролей в приложении, надо добавить его определение в файл конфигурации. Откроем файл web.config и в пределах узла system.web добавим наш провайдер:

<authentication mode="Forms">
   <forms name="cookies" loginUrl="~/Account/Login" />
</authentication>
<roleManager enabled="true" defaultProvider="MyRoleProvider">
   <providers>
     <add name="MyRoleProvider" type="CustomRoleProviderApp.Providers.CustomRoleProvider" />
   </providers>
</roleManager>

И в конце добавим контроллер AccountController для логина и регистрации:

using System.Linq;
using System.Web.Mvc;
using System.Web.Security;
using CustomRoleProviderApp.Models;

namespace CustomRoleProviderApp.Controllers
{
    public class AccountController : Controller
    {
        UserContext db = new UserContext();
        public ActionResult Login()
        {
            return View();
        }
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Login(LoginModel model)
        {
            if (ModelState.IsValid)
            {
                // поиск пользователя в бд
                User user = db.Users.FirstOrDefault(u => u.Email == model.Name && u.Password == model.Password);
                
                if (user != null)
                {
                    FormsAuthentication.SetAuthCookie(model.Name, true);
                    return RedirectToAction("Index", "Home");
                }
                else
                {
                    ModelState.AddModelError("", "Пользователя с таким логином и паролем нет");
                }
            }
            return View(model);
        }

        public ActionResult Register()
        {
            return View();
        }
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Register(RegisterModel model)
        {
            if (ModelState.IsValid)
            {
                User user = db.Users.FirstOrDefault(u => u.Email == model.Name && u.Password == model.Password);
                
                if (user == null)
                {
                    db.Users.Add(new User { Email = model.Name, Password = model.Password, RoleId = 2 });
                    db.SaveChanges();
                    user = db.Users.Where(u => u.Email == model.Name && u.Password == model.Password).FirstOrDefault();
                    if (user != null)
                    {
                        FormsAuthentication.SetAuthCookie(model.Name, true);
                        return RedirectToAction("Index", "Home");
                    }
                }
                else
                    ModelState.AddModelError("", "Пользователь с таким логином уже существует");
            }
            return View(model);
        }
        public ActionResult Logoff()
        {
            FormsAuthentication.SignOut();
            return RedirectToAction("Index", "Home");
        }
    }
}

В методе Register при добавлении нового пользователя мы ему будем присваивать в роль user. Модели, используемые методами Login и Register, выглядят так:

public class RegisterModel
{
    [Required]
    public string Name { get; set; }

    [Required]
    [DataType(DataType.Password)]
    public string Password { get; set; }

    [Required]
    [DataType(DataType.Password)]
    [Compare("Password", ErrorMessage = "Пароли не совпадают")]
    public string ConfirmPassword { get; set; }
}
public class LoginModel
{
    [Required]
    public string Name { get; set; }

    [Required]
    [DataType(DataType.Password)]
    public string Password { get; set; }
}

И теперь мы можем разграничить доступ к методам различных контроллеров с помощью атрибута Authorize:

public class HomeController : Controller
{
    [Authorize(Roles = "admin")]
    public ActionResult Index()
    {
        return View();
    }
}
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850