active - ASP.NET MVC Cómo crear un proveedor de roles personalizado
windows authentication mvc 5 (1)
Siendo relativamente nuevo en ASP MVC, no estoy seguro de cuál se adaptaría mejor a mis necesidades. Construí un sitio de intranet usando la autenticación de Windows y puedo asegurar los controladores y las acciones usando los roles de Active Directory, por ejemplo
[Authorize(Roles="Administrators")]
[Authorize(Users="DOMAIN/User")]
public ActionResult SecureArea()
{
ViewBag.Message = "This is a secure area.";
return View();
}
Necesito definir mis propios roles de seguridad independientes de los roles AD. La funcionalidad deseada es que los usuarios autenticados tengan acceso a acciones específicas según uno o más roles asociados con su perfil en la base de datos de mi aplicación, por ejemplo: "Gerente", "Usuario", "Invitado", "Analista", "Desarrollador", etc.
¿Cómo creo un proveedor de rol personalizado y / o atributo (s) de autorización personalizado?
EDITAR: editó el título y la pregunta para que otros usuarios puedan identificar el contenido de la publicación.
Mi solución fue crear un proveedor de roles personalizado. Estos son los pasos que tomé, en caso de que alguien más necesite ayuda más adelante:
Crea tu usuario personalizado y las clases de roles
using Microsoft.AspNet.Identity.EntityFramework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Security.Models.Security
{
public class AppRole : IdentityRole
{
}
}
y
using Microsoft.AspNet.Identity.EntityFramework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Security.Models.Security
{
public class AppUser : IdentityUser
{
}
}
Configure su contexto de base de datos
using Microsoft.AspNet.Identity.EntityFramework;
using Security.Models.Security;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;
namespace Security.Models.DAL
{
public class UserContext : IdentityDbContext<AppUser>
{
public UserContext() : base("UserContext")
{
Database.SetInitializer<UserContext>(new CreateDatabaseIfNotExists<UserContext>());
}
}
}
Crea tu proveedor de roles e implementa los siguientes métodos
using Security.Models.DAL;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
namespace Security.Models.Security
{
public class AppRoleProvider : RoleProvider
{
public override string[] GetAllRoles()
{
using (var userContext = new UserContext())
{
return userContext.Roles.Select(r => r.Name).ToArray();
}
}
public override string[] GetRolesForUser(string username)
{
using (var userContext = new UserContext())
{
var user = userContext.Users.SingleOrDefault(u => u.UserName == username);
var userRoles = userContext.Roles.Select(r => r.Name);
if (user == null)
return new string[] { };
return user.Roles == null ? new string[] { } :
userRoles.ToArray();
}
}
public override bool IsUserInRole(string username, string roleName)
{
using (var userContext = new UserContext())
{
var user = userContext.Users.SingleOrDefault(u => u.UserName == username);
var userRoles = userContext.Roles.Select(r => r.Name);
if (user == null)
return false;
return user.Roles != null &&
userRoles.Any(r => r == roleName);
}
}
}
}
Edite su web.config para configurar la conexión a la base de datos y la referencia del proveedor de roles
<connectionStrings>
<add name="UserContext" connectionString="Data Source=(LocalDb)/MSSQLLocalDB;AttachDbFilename=|DataDirectory|/UserContext.mdf;Initial Catalog=UserContext;Integrated Security=SSPI;" providerName="System.Data.SqlClient" />
</connectionStrings>
y
<system.web>
...
<authentication mode="Windows" />
<roleManager enabled="true" defaultProvider="AppRoleProvider">
<providers>
<clear/>
<add name="AppRoleProvider" type="Security.Models.Security.AppRoleProvider" connectionStringName = "UserContext"/>
</providers>
...
</roleManager>
</system.web>
En la consola del administrador de paquetes, habilite las migraciones
enable-migrations
En las Configuraciones.cs recientemente creadas, configure las administraciones y los almacenes de usuarios / roles y configure el validador del administrador de usuarios para aceptar ''/' caracteres
namespace Security.Migrations
{
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Security.Models.Security;
using System;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Linq;
internal sealed class Configuration : DbMigrationsConfiguration<Security.Models.DAL.UserContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
ContextKey = "Security.Models.DAL.UserContext";
}
protected override void Seed(Security.Models.DAL.UserContext db)
{
// Set up the role store and the role manager
var roleStore = new RoleStore<AppRole>(db);
var roleManager = new RoleManager<AppRole>(roleStore);
// Set up the user store and the user mananger
var userStore = new UserStore<AppUser>(db);
var userManager = new UserManager<AppUser>(userStore);
// Ensure that the user manager is able to accept special characters for userNames (e.g. ''/' in the ''DOMAIN/username'')
userManager.UserValidator = new UserValidator<AppUser>(userManager) { AllowOnlyAlphanumericUserNames = false };
// Seed the database with the administrator role if it does not already exist
if (!db.Roles.Any(r => r.Name == "Administrator"))
{
var role = new AppRole { Name = "Administrator" };
roleManager.Create(role);
}
// Seed the database with the administrator user if it does not already exist
if (!db.Users.Any(u => u.UserName == @"DOMAIN/admin"))
{
var user = new AppUser { UserName = @"DOMAIN/admin" };
userManager.Create(user);
// Assign the administrator role to this user
userManager.AddToRole(user.Id, "Administrator");
}
}
}
}
En la consola del gestor de paquetes, asegúrese de que la base de datos esté creada y sembrada
update-database
Cree un atributo de autorización personalizado que redirija a una página de acceso denegado en caso de error
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Security.Models.Security
{
public class AccessDeniedAuthorizationAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
if(filterContext.Result is HttpUnauthorizedResult)
{
filterContext.Result = new RedirectResult("~/Home/AccessDenied");
}
}
}
}
¡Terminaste! Ahora puede crear una página de acceso denegado (en este caso ~ / Home / AccessDenied) y aplicar el atributo a cualquier acción, por ejemplo
using Security.Models.Security;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Security.Controllers
{
public class HomeController : Controller
{
...
[AccessDeniedAuthorizationAttribute(Roles = "Administrator")]
public ActionResult SecureArea()
{
return View();
}
public ActionResult AccessDenied()
{
return View();
}
...
}
}
Espero que esto ayude a alguien en el futuro. ¡Buena suerte!