例如:一个组织可以有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
名称 | 描述 |
CreateAsync(role) | 创建一个新的角色 |
DeleteAsync(role) | 删除一个指定的角色 |
FindByIdAsync(id) | 根据角色Id查找一个角色 |
FindByNameAsync(name) | 根据角色名称查找一个角色 |
RoleExistsAsync(name) | 根据角色名称检查角色是否存在 |
UpdateAsync(name) | 更新角色 |
Roles | 返回Identity中的所有角色 |
2、Identity中角色管理
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;}
RoleManager类Roles属性提供了Identity所有的角色,我们将所有的Roles作为模型类传递给Index视图,代码如下:
public IActionResult Index(){return View(_roleManager.Roles);}
@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>
接下来在项目根目录一下创建一个文件夹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; } = null!;public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output){List<string> names = new List<string>();var role = await _roleManager.FindByIdAsync(Role);if (role != null){foreach (var user in _userManager.Users){if (user != null && 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创建角色
我们使用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");elseErrors(result);}return View(name);}
CreateAsync方法入参是name(角色名称)的字符串参数并且使用RoleManager的CreateAsync()方法来创建一个Identity Role
var result = await _roleManager.CreateAsync(new IdentityRole(name));@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 != null){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创建和删除角色功能

我们可以通过这个删除按钮删除Identity 数据库中的Role:

添加用户到指定角色 将用户从角色中移除
为了实现这个功能,我们在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; } = null!;public string RoleId { get; set; } = null!;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 });}
[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 != null){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 != null){var identityResult = await _userManager.RemoveFromRoleAsync(appUser, roleModification.RoleName);if (!identityResult.Succeeded)Errors(identityResult);}}}if (ModelState.IsValid)return RedirectToAction(nameof(Index));elsereturn await UpdateAsync(roleModification.RoleId);}
private RoleManager<IdentityRole> _roleManager;private UserManager<AppUser> _userManager;public RoleController(RoleManager<IdentityRole> roleManager, UserManager<AppUser> userManager){_roleManager = roleManager;_userManager = userManager;}
名称 | 描述 |
AddToRoleAsync(AppUser user, string name) | 将用户添加到指定角色中 |
RemoveFromRoleAsync(AppUser user, string name) | 从指定角色中删除用户 |
GetRolesAsync(AppUser user) | 获取当前用户所有角色 |
IsInRoleAsync(AppUser user, string name) | 判断一个用户是否是指定的角色成员如果是返回ture,否则false |
@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:
当前角色包含的用户 当前角色未包含的用户
测试更新功能
我们先注册三个用户(密码为:Coder77@1):






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所拥有的角色是Manager。现在我们使用alice 用户进行登录,alice不属于Manager角色,所以当我们尝试访问Home/Index时,应用程序将会跳转到https://localhost:7296
/Account/AccessDenied?ReturnUrl=%2F,因为AccountCon
public IActionResult AccessDenied(){return View();}
<h2>Access Denied</h2><a asp-controller="Account" asp-action="Logout" class="btn btn-primary">退出登录</a>
邮箱–alice@yahoo.com
密码– Coder77@1

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;});
总结
源代码地址:
https://github.com/bingbing-gui/Asp.Net-Core-Skill/tree/master/AspNetCore.Identity/Identity