使用 ASP.NET Core Identity 3 的用户角色权限
Users Roles Permissions using ASP.NET Core Identity 3
我被困在一个我想在 asp.net mvc 核心应用程序中提供的解决方案上。我想为利用新的基于声明的方法的 Web 应用程序中的标准用户、角色和权限提供解决方案。
我一直在遵循 Ben Foster 的逻辑 (http://benfoster.io/blog/asp-net-identity-role-claims)。在下面的代码(演示质量)中,我说明了我的方法,我将对其进行评论以帮助展示我的快速和肮脏的测试解决方案。
我面临的挑战是它不起作用。
//注意:我已经找到了这个错误,并且会为未来寻找类似解决方案的用户评论我出错的地方。
种子Class:这是一个快速而肮脏的解决方案,用于为数据库植入两个新用户、两个角色和其中一个角色的一些声明。我这样做是作为一个测试应用程序来学习管理我的应用程序授权的声明方法。我的完整解决方案将为每个租户提供一种通过 UI 创建自己的角色的方法,将一个或多个声明关联到角色,然后将角色分配给用户。我想为租户提供一种方式来管理他们自己的用户以及他们可以做什么或不能做什么。这是基于声明的方法的简单实现,因为声明比 1:1 与政策的关系更有力量。
public class DbInitializer
{
private ApplicationDbContext _context;
private RoleManager<ApplicationRole> _roleManager;
private UserManager<ApplicationUser> _userManager;
public DbInitializer(ApplicationDbContext context,RoleManager<ApplicationRole> roleManager, UserManager<ApplicationUser> userManager)
{
_roleManager = roleManager;
_userManager = userManager;
_context = context;
}
public async Task Initialize()
{
//RoleManager<IdentityRole> roleManager = new RoleManager<IdentityRole>();
//UserManager<ApplicationUser> userManager = new UserManager<ApplicationUser>();
_context.Database.EnsureCreated();
// Look for any students.
if (!_context.Users.Any())
{
//create user and admin role
ApplicationUser adminUser = new ApplicationUser();
adminUser.Email = "admin@company.com";
adminUser.UserName = "Admin";
var result = await _userManager.CreateAsync(adminUser, "Password-1");
var newAdminUser = await _userManager.FindByEmailAsync(adminUser.Email);
ApplicationRole adminRole = new ApplicationRole();
adminRole.Name = "Admin";
adminRole.Description = "This is the admin role.";
await _roleManager.CreateAsync(adminRole);
await _roleManager.AddClaimAsync(adminRole, new Claim("Can add roles", "add.role"));
await _roleManager.AddClaimAsync(adminRole, new Claim("Can delete roles", "delete.role"));
await _roleManager.AddClaimAsync(adminRole, new Claim("Can edit roles", "edit.role"));
await _userManager.AddToRoleAsync(newAdminUser, adminRole.Name);
//create user and basic role
ApplicationUser basicUser = new ApplicationUser();
basicUser.Email = "basic@company.com";
basicUser.UserName = "Basic";
var resultBasic = await _userManager.CreateAsync(basicUser, "Password-1");
var newBasicUser = await _userManager.FindByEmailAsync(basicUser.Email);
ApplicationRole basicRole = new ApplicationRole();
basicRole.Name = "Basic";
basicRole.Description = "This is the basic role.";
await _roleManager.CreateAsync(basicRole);
//await _roleManager.AddClaimAsync(basicRole, new Claim("Can add roles", "add.role"));
//await _roleManager.AddClaimAsync(basicRole, new Claim("Can delete roles", "delete.role"));
//await _roleManager.AddClaimAsync(basicRole, new Claim("Can edit roles", "edit.role"));
await _userManager.AddToRoleAsync(newBasicUser, basicRole.Name);
await _context.SaveChangesAsync();
}
}
}
}
Startup.CS:创建我的用户、角色和声明(并关联它们)后,我需要在 Startup.cs class 配置服务方法中注册 'Policies' .这允许我将声明映射到一个或多个策略。
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddAuthorization(options =>
{
options.AddPolicy("Add Role",
policy => policy.RequireClaim("Can add roles", "add.role"));
options.AddPolicy("Edit Role",
policy => policy.RequireClaim("Can edit roles", "edit.role"));
options.AddPolicy("Delete Role",
policy => policy.RequireClaim("Can delete roles", "delete.role"));
});
services.AddMvc();
services.AddTransient<DbInitializer>();
// Add application services.
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
}
View:在我的用例中,我想限制任何没有 "Can add roles" 声明与其分配给的角色相关联的用户的 'Add Role' 按钮。其余的视图代码不相关。我 运行 遇到的问题是,我将声明名称作为第二个参数传递给了 AuthorizationService.AuthorizeAsync,而 'Policy' 名称与声明相关联。我已经在下面更正了它。
@model IEnumerable<ApplicationRoleListViewModel>
@using HailMarry.Models
@using Microsoft.AspNetCore.Authorization
@inject IAuthorizationService AuthorizationService
<br />
<div class="top-buffer"></div>
<div class="panel panel-primary">
<div class="panel-heading panel-head">Application Roles</div>
<div class="panel-body">
<div class="btn-group">
//Mistake
//@if (await AuthorizationService.AuthorizeAsync(User, "Can add roles"))
//Fix
@if (await AuthorizationService.AuthorizeAsync(User, "Add Role"))
{
<a id="createRoleButton" asp-action="AddRole" asp-controller="ApplicationRole" class="btn btn-primary">
<i class="glyphicon glyphicon-plus"></i> Add Role
</a>
}
....
最终结果:我有一个用户 "admin@company.com",它被分配到一个角色 "Admin",该角色具有声明 "Can add roles"。一个角色可以有任意数量的声明。我创建了一个策略,它具有与我通过可注入的 IAuthorizationService AuthorizationService 在视图中检查的相同的声明 "Can add roles"。如果用户没有将此声明分配给他们的角色,则策略检查 returns true 或 false 将不会显示添加角色的按钮。由于新的 .net 核心 DI 中间件,可以将相同的策略检查逻辑添加到控制器或通过 DI 的任何其他资源。通过整个练习,我了解了 Identity 3 的强大功能,它可以利用业务逻辑检查等功能。非常甜蜜的东西,虽然那里的作家真的需要更多的例子来帮助我们更快地切入主题。无论如何,希望这对未来寻找类似解决方案的开发人员有所帮助。
我发现了问题,我引用了声明 'name' 与视图中的保单名称...
我将在上面添加注释来说明错误并展示我在做什么。非常强大的东西,感谢 Ben 和 ASP.Net 改进了 4.5 以上的授权解决方案。
我被困在一个我想在 asp.net mvc 核心应用程序中提供的解决方案上。我想为利用新的基于声明的方法的 Web 应用程序中的标准用户、角色和权限提供解决方案。
我一直在遵循 Ben Foster 的逻辑 (http://benfoster.io/blog/asp-net-identity-role-claims)。在下面的代码(演示质量)中,我说明了我的方法,我将对其进行评论以帮助展示我的快速和肮脏的测试解决方案。
我面临的挑战是它不起作用。
//注意:我已经找到了这个错误,并且会为未来寻找类似解决方案的用户评论我出错的地方。
种子Class:这是一个快速而肮脏的解决方案,用于为数据库植入两个新用户、两个角色和其中一个角色的一些声明。我这样做是作为一个测试应用程序来学习管理我的应用程序授权的声明方法。我的完整解决方案将为每个租户提供一种通过 UI 创建自己的角色的方法,将一个或多个声明关联到角色,然后将角色分配给用户。我想为租户提供一种方式来管理他们自己的用户以及他们可以做什么或不能做什么。这是基于声明的方法的简单实现,因为声明比 1:1 与政策的关系更有力量。
public class DbInitializer
{
private ApplicationDbContext _context;
private RoleManager<ApplicationRole> _roleManager;
private UserManager<ApplicationUser> _userManager;
public DbInitializer(ApplicationDbContext context,RoleManager<ApplicationRole> roleManager, UserManager<ApplicationUser> userManager)
{
_roleManager = roleManager;
_userManager = userManager;
_context = context;
}
public async Task Initialize()
{
//RoleManager<IdentityRole> roleManager = new RoleManager<IdentityRole>();
//UserManager<ApplicationUser> userManager = new UserManager<ApplicationUser>();
_context.Database.EnsureCreated();
// Look for any students.
if (!_context.Users.Any())
{
//create user and admin role
ApplicationUser adminUser = new ApplicationUser();
adminUser.Email = "admin@company.com";
adminUser.UserName = "Admin";
var result = await _userManager.CreateAsync(adminUser, "Password-1");
var newAdminUser = await _userManager.FindByEmailAsync(adminUser.Email);
ApplicationRole adminRole = new ApplicationRole();
adminRole.Name = "Admin";
adminRole.Description = "This is the admin role.";
await _roleManager.CreateAsync(adminRole);
await _roleManager.AddClaimAsync(adminRole, new Claim("Can add roles", "add.role"));
await _roleManager.AddClaimAsync(adminRole, new Claim("Can delete roles", "delete.role"));
await _roleManager.AddClaimAsync(adminRole, new Claim("Can edit roles", "edit.role"));
await _userManager.AddToRoleAsync(newAdminUser, adminRole.Name);
//create user and basic role
ApplicationUser basicUser = new ApplicationUser();
basicUser.Email = "basic@company.com";
basicUser.UserName = "Basic";
var resultBasic = await _userManager.CreateAsync(basicUser, "Password-1");
var newBasicUser = await _userManager.FindByEmailAsync(basicUser.Email);
ApplicationRole basicRole = new ApplicationRole();
basicRole.Name = "Basic";
basicRole.Description = "This is the basic role.";
await _roleManager.CreateAsync(basicRole);
//await _roleManager.AddClaimAsync(basicRole, new Claim("Can add roles", "add.role"));
//await _roleManager.AddClaimAsync(basicRole, new Claim("Can delete roles", "delete.role"));
//await _roleManager.AddClaimAsync(basicRole, new Claim("Can edit roles", "edit.role"));
await _userManager.AddToRoleAsync(newBasicUser, basicRole.Name);
await _context.SaveChangesAsync();
}
}
}
}
Startup.CS:创建我的用户、角色和声明(并关联它们)后,我需要在 Startup.cs class 配置服务方法中注册 'Policies' .这允许我将声明映射到一个或多个策略。
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddAuthorization(options =>
{
options.AddPolicy("Add Role",
policy => policy.RequireClaim("Can add roles", "add.role"));
options.AddPolicy("Edit Role",
policy => policy.RequireClaim("Can edit roles", "edit.role"));
options.AddPolicy("Delete Role",
policy => policy.RequireClaim("Can delete roles", "delete.role"));
});
services.AddMvc();
services.AddTransient<DbInitializer>();
// Add application services.
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
}
View:在我的用例中,我想限制任何没有 "Can add roles" 声明与其分配给的角色相关联的用户的 'Add Role' 按钮。其余的视图代码不相关。我 运行 遇到的问题是,我将声明名称作为第二个参数传递给了 AuthorizationService.AuthorizeAsync,而 'Policy' 名称与声明相关联。我已经在下面更正了它。
@model IEnumerable<ApplicationRoleListViewModel>
@using HailMarry.Models
@using Microsoft.AspNetCore.Authorization
@inject IAuthorizationService AuthorizationService
<br />
<div class="top-buffer"></div>
<div class="panel panel-primary">
<div class="panel-heading panel-head">Application Roles</div>
<div class="panel-body">
<div class="btn-group">
//Mistake
//@if (await AuthorizationService.AuthorizeAsync(User, "Can add roles"))
//Fix
@if (await AuthorizationService.AuthorizeAsync(User, "Add Role"))
{
<a id="createRoleButton" asp-action="AddRole" asp-controller="ApplicationRole" class="btn btn-primary">
<i class="glyphicon glyphicon-plus"></i> Add Role
</a>
}
....
最终结果:我有一个用户 "admin@company.com",它被分配到一个角色 "Admin",该角色具有声明 "Can add roles"。一个角色可以有任意数量的声明。我创建了一个策略,它具有与我通过可注入的 IAuthorizationService AuthorizationService 在视图中检查的相同的声明 "Can add roles"。如果用户没有将此声明分配给他们的角色,则策略检查 returns true 或 false 将不会显示添加角色的按钮。由于新的 .net 核心 DI 中间件,可以将相同的策略检查逻辑添加到控制器或通过 DI 的任何其他资源。通过整个练习,我了解了 Identity 3 的强大功能,它可以利用业务逻辑检查等功能。非常甜蜜的东西,虽然那里的作家真的需要更多的例子来帮助我们更快地切入主题。无论如何,希望这对未来寻找类似解决方案的开发人员有所帮助。
我发现了问题,我引用了声明 'name' 与视图中的保单名称...
我将在上面添加注释来说明错误并展示我在做什么。非常强大的东西,感谢 Ben 和 ASP.Net 改进了 4.5 以上的授权解决方案。