那节我们将介绍在Identity中若何利用Role,在我们应用法式中能够通过ASP.NET Core Identity创建Roles而且该角色能够包罗一系列权限来施行应用法式的一系列活动

例如:一个组织能够有4个角色:

1.Admin – 办理员角色给员工分配工做

2.Manager –查看客户需求并定时完成项目

3.Network –用于连结组织的互联网以平安的体例运行。

4.Security - 系统平安相关权限

在ASP.NET Core Identity 我们能创建任何数量的Roles而且能够将那些Roles赋值给Identity Users

1、ASP.NET Core Identity RoleManager类

我们利用ASP.NET Core Identity RoleManager来办理Role,RoleManager<T> 泛型版本T暗示Identity在数据库中的Roles

RoleManager定义了一些重要的功用和属性:

名称

描述

CreateAsync(role)

创建一个新的角色

DeleteAsync(role)

删除一个指定的角色

FindByIdAsync(id)

按照角色Id查找一个角色

FindByNameAsync(name)

按照角色名称查找一个角色

RoleExistsAsync(name)

按照角色名称查抄角色能否存在

UpdateAsync(name)

更新角色

Roles

返回Identity中的所有角色

2、Identity中角色办理

我们利用ASP.NET Core Identity实现一个创建和删除角色的功用,创建一个名字为RoleController.cs而且添加如下代码:public class RoleController : Controller{ PRivate RoleManager<IdentityRole> _roleManager; public RoleController(RoleManager<IdentityRole> roleManager) { _roleManager = roleManager; } public IActionResult Index() => View(_roleManager.Roles); private void Errors(IdentityResult result) { foreach (IdentityError error in result.Errors) ModelState.AddModelError("", error.Description); }}

在RoleController中,通过构造函数注入了RoleManager类,我们能够通过依赖注入获取到该类,并利用它来办理Identity角色

private RoleManager<IdentityRole> _roleManager;public RoleController(RoleManager<IdentityRole> roleManager){ _roleManager = roleManager;}获取所有Identity的角色

RoleManager类Roles属性供给了Identity所有的角色,我们将所有的Roles做为模子类传递给Index视图,代码如下:

public IActionResult Index(){ return View(_roleManager.Roles);}接下来我们在View->Role文件夹下创建一个Index.cshtml文件@using Microsoft.AspNetCore.Identity;@model IEnumerable<IdentityRole>@{ ViewData["Title"] = "Roles";}<div class="container"> <div class="row mb-3"> <div class="col-sm-3"> <a asp-action="Create" class="btn btn-primary">新增</a> </div> <div class="col-sm-3"></div> <div class="col-sm-3"></div> <div class="col-sm-3"></div> </div> <div class="row mb-3"> <div class="col-sm"> <table class="table-content-center table table-bordered"> <thead> <tr> <th>编号</th> <th>角色名称</th> <td>用户</td> <th>编纂</th> <td>删除</td> </tr> </thead> <tbody> @foreach (var role in Model) { <tr> <td>@role.Id</td> <td>@role.Name</td> <td i-role="@role.Id"></td> <td> <a class="btn btn-primary btn-sm" asp-action="Update" asp-route-id="@role.Id">编纂</a> </td> <td> <form method="post" asp-action="Delete" asp-route-id="@role.Id" role="form"> <button tyPE="submit" class="btn btn-danger btn-sm">删除</button> </form> </td> </tr> } </tbody> </table> </div> </div></div>那个视图中获取了一个IEnumerable<IdentityRole>类型集合,它将包罗Identity所有Role,我们通过foreach轮回将所有Role展现在table内,留意i-role我们利用了第三方Attribute,那个Attribute将挪用客户自定义的TagHelper,那个特征会修改td并显示当前角色的用户列表

接下来在项目根目次一下创建一个文件夹CustomTagHelpers,在该文件夹下添加一个RoleUsersTH.cs类,而且该类继承TagHelper,那个类供给自定义的CustomerTagHelper

/// <summary> /// 自定义TagHelper /// </summary> [HtmlTargetElement("td", Attributes = "i-role")] public class RoleUsersTH : TagHelper { private UserManager<AppUser> _userManager; private RoleManager<IdentityRole> _roleManager; public RoleUsersTH(UserManager<AppUser> userManager, RoleManager<IdentityRole> roleManager) { _userManager = userManager; _roleManager = roleManager; } [HtmlAttributeName("i-role")] public string Role { get; set; } = !; public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { List<string> names = new List<string>(); var role = await _roleManager.FindByIdAsync(Role); if (role != ) { foreach (var user in _userManager.Users) { if (user != && await _userManager.IsInRoleAsync(user, role.Name ?? "")) names.Add(user.UserName ?? ""); } } output.Content.SetContent(names.Count == 0 ? "No Users" : string.Join(", ", names)); } }

客户自定义的TagHelper操做td中i-role特征,那个特征获取对应的角色ID,并在后台被处置

我们需要更新_ViewImports.cshtml文件

ASP.NET Core Identity 系列之五  第1张

ASP.NET Core Identity创建角色

我们利用RoleManager的CreateAsync办法创建一个Identity Role,在RoleController类中创建一个CreateAsync办法,代码如下:

public IActionResult Create() => View();[HttpPost]public async Task<IActionResult> CreateAsync([Required] string name){ if (ModelState.IsValid) { var result = await _roleManager.CreateAsync(new IdentityRole(name)); if (result.Succeeded) return RedirectToAction("Index"); else Errors(result); } return View(name);}

CreateAsync办法入参是name(角色名称)的字符串参数而且利用RoleManager的CreateAsync()办法来创建一个Identity Role

var result = await _roleManager.CreateAsync(new IdentityRole(name));我们接下来在Views->Role目次下添加一个Create 视图,代码如下:@model IdentityRole@{ ViewData["Title"] = "新增角色";}<div asp-validation-summary="All" class="text-danger"></div><form class="form-horizontal" method="post"> <div class="mb-3 row"> <div class="col-sm-1"> <label for="Name" class="control-label">角色名称:</label> </div> <div class="col-sm-11"> <input asp-for="Name" class="form-control" placeholder="请输入角色名称" /> </div> </div> <div class="mb-3 row"> <div class="col-sm-11 offset-sm-1"> <button type="submit" class="btn btn-primary">保留</button> <button asp-action="Index" class="btn btn-secondary"> 返回 </button> </div> </div></form>

ASP.NET Core Identity删除角色

我们利用RoleManager的DeleteAsync()来删除一个Identity Role, 在RoleController.cs的控造器中创建一个DeleteAsync 办法并承受一个角色id(需要删除的角色),代码如下:

public async Task<IActionResult> DeleteAsync(string id){ var role = await _roleManager.FindByIdAsync(id); if (role != ) { var identityResult = await _roleManager.DeleteAsync(role); if (identityResult.Succeeded) { return RedirectToAction("Index"); } else { Errors(identityResult); } } else { ModelState.AddModelError("", "No role found"); } return View("Index", _roleManager.Roles);}

测试Identity创建和删除角色功用

运行应用法式并将URL导航 https://localhost:7296/Role/Create每次创建完一个角色就会跳转到Index View显示Identity数据库中所有的角色创建role页面如下:

ASP.NET Core Identity 系列之五  第2张

我们能够通过那个删除按钮删除Identity 数据库中的Role:

ASP.NET Core Identity 系列之五  第3张

3、添加用户到Roles或从Roles中移除用户如今我们创建一个新的功用,将完成两件工作:添加用户到指定角色将用户从角色中移除

为了实现那个功用,我们在Models文件加下添加两个类,别离为RoleEdit和RoleModification

public class RoleEdit{ public IdentityRole? Role { get; set; } public IEnumerable<AppUser>? Members { get; set; } public IEnumerable<AppUser>? NoMembers { get; set; }}

RoleEdit暗示一个角色和他联系关系的用户以及和该角色未联系关系的用户,RoleModification那个类将帮忙我们修改一个角色,详细定义如下:

public class RoleModification{ [Required] public string RoleName { get; set; } = !; public string RoleId { get; set; } = !; public string[]? AddIds { get; set; } public string[]? DeleteIds { get; set; }}

那两个类帮忙我们将一个用户添加到角色中和从角色中移除用户,我们修改一些RoleController类,添加UpdateAsync办法,下面Get版本的UpdateAsync办法查询两部门数据,属于该角色的用户和不属于该角色的用户

public async Task<IActionResult> UpdateAsync(string id){ var role = await _roleManager.FindByIdAsync(id); List<AppUser> members = new List<AppUser>(); List<AppUser> nonMembers = new List<AppUser>(); foreach (var appUser in _userManager.Users) { var list = await _userManager.IsInRoleAsync(appUser, role?.Name ?? "") ? members : nonMembers; list.Add(appUser); } return View(new RoleEdit() { Role = role, Members = members, NoMembers = nonMembers });}下面Post版本的UpdateAsync办法暗示给用户添加和移除角色[HttpPost] public async Task<IActionResult> UpdateAsync(RoleModification roleModification) { if (ModelState.IsValid) { foreach (var userId in roleModification.AddIds ?? new string[] { }) { var appUser = await _userManager.FindByIdAsync(userId); if (appUser != ) { var identityResult = await _userManager.AddToRoleAsync(appUser, roleModification.RoleName); if (!identityResult.Succeeded) Errors(identityResult); } } foreach (var userId in roleModification.DeleteIds ?? new string[] { }) { var appUser = await _userManager.FindByIdAsync(userId); if (appUser != ) { var identityResult = await _userManager.RemoveFromRoleAsync(appUser, roleModification.RoleName); if (!identityResult.Succeeded) Errors(identityResult); } } } if (ModelState.IsValid) return RedirectToAction(nameof(Index)); else return await UpdateAsync(roleModification.RoleId); }留意我们在构造函数中添加了UserManager依赖:private RoleManager<IdentityRole> _roleManager;private UserManager<AppUser> _userManager;public RoleController(RoleManager<IdentityRole> roleManager, UserManager<AppUser> userManager){ _roleManager = roleManager; _userManager = userManager;}我们利用UserManager类的下面办法类办理ASP.NET Core Identity Roles

名称

描述

AddToRoleAsync(AppUser user, string name)

将用户添加到指定角色中

RemoveFromRoleAsync(AppUser user, string name)

从指定角色中删除用户

GetRolesAsync(AppUser user)

获取当前用户所有角色

IsInRoleAsync(AppUser user, string name)

判断一个用户能否是指定的角色成员若是是返回ture,不然false

接下来,在Views -> Role 文件夹下添加Update.csthml,代码如下:@model RoleEdit@{ ViewData["Title"] = "编纂角色";}<div asp-validation-summary="All" class="text-danger"></div><style> .table-column-width td { width: 200px }</style><form class="form" method="post" role="form"> <input type="hidden" name="roleName" value="@Model.Role?.Name" /> <input type="hidden" name="roleId" value="@Model.Role?.Id" /> <h2><small> @Model.Role.Name 角色包罗的用户</small></h2> <table class="table-column-width table table-bordered"> @if (!Model.Members!.Any()) { <tr> <td>该角色没有联系关系任何用户</td> </tr> } else { foreach (var appUser in Model.Members ?? new List<AppUser>()) { <tr> <td>@appUser.UserName</td> <td> <input type="checkbox" name="DeleteIds" value="@appUser.Id" /> </td> </tr> } } </table> <h2><small> @Model.Role.Name 角色未包罗的用户</small></h2> <table class="table-column-width table table-bordered"> @if (!Model.NoMembers!.Any()) { <tr> <td>该角色庇护所有用户</td> </tr> } else { foreach (var appUser in Model.NoMembers ?? new List<AppUser>()) { <tr> <td>@appUser.UserName</td> <td> <input type="checkbox" name="AddIds" value="@appUser.Id" /> </td> </tr> } } </table> <button class="btn btn-primary">保留</button> <button asp-action="index" class="btn btn-secondary">返回</button></form>

那个页面包罗两个Table:

当前角色包罗的用户当前角色未包罗的用户我们能够选择对应的 checkbox给角色添加和删除用户

测试更新功用

我们先注册三个用户(密码为:Coder77@1):

ASP.NET Core Identity 系列之五  第4张

同时我们也创建了三个角色:ASP.NET Core Identity 系列之五  第5张我们查看当前每个角色都没有用户:

ASP.NET Core Identity 系列之五  第6张

ASP.NET Core Identity 系列之五  第7张

ASP.NET Core Identity 系列之五  第8张

ASP.NET Core Identity 系列之五  第9张一个用户能够指定多个角色,利用那个功用仅仅完成了ASP.NET Core Identity 更新角色的功用,下面我们将实现基于角色的认证4、基于ASP.NET Core Identity Role 认证ASP.NET Core Identity 角色能够做为认证,特定角色所包罗的用户能拜候特定的资本。例如:我们给指定办法设定一个[Authorize(Roles = “SomeRole”)]特征,那个角色下的所有用户都能拜候那个办法在HomeController的Index办法添加Authorize特征[Authorize(Roles = "Manager")] , 指明只要Manager角色的用户才气拜候HomeController的Index 办法,代码如下:public class HomeController : Controller{ private readonly ILogger<HomeController> _logger; private UserManager<AppUser> _userManager; public HomeController(UserManager<AppUser> userManager, ILogger<HomeController> logger) { _userManager = userManager; _logger = logger; } [Authorize(Roles = "Manager")] public async Task<IActionResult> Index() { var appUser = await _userManager.GetUserAsync(HttpContext.User); var message = "Hello " + appUser?.UserName; return View((object)message); }}运行应用法式,利用tom登录,拜候HomeController办法我们能够一般拜候HomeController的Index办法

因为tom所拥有的角色是Manager。如今我们利用alice 用户停止登录,alice不属于Manager角色,所以当我们测验考试拜候Home/Index时,应用法式将会跳转到https://localhost:7296

/Account/AccessDenied?ReturnUrl=%2F,因为AccountCon

troller控造器中没有创建AccessDenied办法,因而会获取一个HTTP 404 错误,因而我们在ActionController下创建一个AccessDenied办法:public IActionResult AccessDenied(){ return View();}在Views->Account目次下添加AccessDenied.cshtml视图,代码如下:<h2>Access Denied</h2><a asp-controller="Account" asp-action="Logout" class="btn btn-primary">退出登录</a>如今,运行应用法式,并进入登录页面https://localhost:7296/Account/Login.利用 alice账户登录:

邮箱–alice@yahoo.com

密码– Coder77@1

登录之后将被调转到Denied URL, 如下图所示:

ASP.NET Core Identity 系列之五  第10张

Identity为我们供给设置了一个默认的/Account/AccessDenied URL地址,我们能够通过设置装备摆设改动那个地址:builder.Services.ConfigureApplicationCookie( opts => { //默认登录页面 opts.LoginPath = "/Account/Login"; opts.AccessDeniedPath= "/Account/AccessDenied"; //设置Cookie名称 opts.Cookie.Name = ".AspNetCore.Identity.Application"; //设置Cookie超不时间 opts.ExpireTimeSpan = TimeSpan.FromMinutes(20); //设置滑动时间 opts.SlidingExpiration = true; });

总结

那节我们次要讲解了Identity角色办理和身份认证

源代码地址:

https://github.com/bingbing-gui/Asp.Net-Core-Skill/tree/master/AspNetCore.Identity/Identity