Étant relativement nouveau à ASP MVC, je ne sais pas ce qui conviendrait mieux à mes besoins. J'ai construit un site intranet utilisant l'authentification Windows et je suis en mesure de sécuriser les contrôleurs et les actions en utilisant Active Directory rôles, par exemple.
[Authorize(Roles="Administrators")]
[Authorize(Users="DOMAIN\User")]
public ActionResult SecureArea()
{
ViewBag.Message = "This is a secure area.";
return View();
}
J'ai besoin de définir mes propres rôles de sécurité indépendamment des rôles AD. La fonctionnalité souhaitée est que les utilisateurs authentifiés ont accès à des actions spécifiques en fonction d'un ou plusieurs rôles associés à leur profil dans ma base de données d'application, par exemple: "Manager", "User", "Guest", "Analyst", "Developer" etc.
Comment créer un fournisseur de rôle personnalisé et/ou des attributs d'autorisation personnalisés?
Ma solution était de créer un fournisseur de rôles personnalisé. Voici les étapes que j'ai prises, au cas où quelqu'un d'autre aurait besoin d'aide plus tard:
Créez vos classes d'utilisateurs et de rôles personnalisées
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
{
}
}
et
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
{
}
}
Configurez le contexte de votre base de données
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>());
}
}
}
Créez votre fournisseur de rôles et implémentez les méthodes suivantes
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);
}
}
}
}
Modifiez votre web.config pour configurer la connexion à la base de données et la référence du fournisseur de rôle
<connectionStrings>
<add name="UserContext" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\UserContext.mdf;Initial Catalog=UserContext;Integrated Security=SSPI;" providerName="System.Data.SqlClient" />
</connectionStrings>
et
<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>
Dans la console du gestionnaire de packages, activez les migrations
enable-migrations
Dans les Configurations.cs nouvellement créées, configurez les magasins d'utilisateurs/rôles et les gestionnaires et configurez le validateur du gestionnaire d'utilisateurs pour accepter les caractères '\'
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");
}
}
}
}
Dans la console du gestionnaire de packages, assurez-vous que la base de données est créée et amorcée
update-database
Créez un attribut d'autorisation personnalisé qui redirigera vers une page d'accès refusé en cas d'échec
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");
}
}
}
}
Vous avez terminé! Vous pouvez maintenant créer une page d'accès refusé (dans ce cas ~/Accueil/AccessDenied) et appliquer l'attribut à n'importe quelle action, par exemple.
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();
}
...
}
}
J'espère que cela aidera quelqu'un à l'avenir. Bonne chance!