篇(15)-Asp.Net Core入门实战-权限管理之用户创建与关联角色(ViewModel再用与模型验证一)
在上个篇章中,讲了角色和菜单的关系(也就是给角色赋权),本章讲用户和给用户分派角色的功能。如果是小白,最好是仔细看我写的代码,因为关键代码处都有注解。建议将篇14和篇15阅读完毕再做演练,为防止单篇过长,我将其分成2篇来讲解。
用户与角色的处理逻辑是:(1).用户的增删改查;(2).给用户选一个所属角色。
1.用户管理功能
(1).用户表(Sql库)的创建
 - CREATE TABLE [dbo].[Manager](
- [Id] [int] IDENTITY(1,1) NOT NULL,
- [RoleId] [int] NOT NULL,
- [UserName] [varchar](32) NOT NULL,
- [Password] [varchar](128) NOT NULL,
- [Avatar] [varchar](256) NULL,
- [NickName] [varchar](32) NULL,
- [Mobile] [varchar](16) NULL,
- [Email] [varchar](128) NULL,
- [LoginCount] [int] NULL,
- [LoginLastIp] [varchar](64) NULL,
- [LoginLastTime] [datetime] NULL,
- [AddManagerId] [int] NOT NULL,
- [AddTime] [datetime] NOT NULL,
- [ModifyManagerId] [int] NULL,
- [ModifyTime] [datetime] NULL,
- [IsLock] [bit] NOT NULL,
- [IsDelete] [bit] NOT NULL,
- [Remark] [varchar](128) NULL,
- CONSTRAINT [PK_MANAGER] PRIMARY KEY NONCLUSTERED
- (
- [Id] ASC
- )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
- ) ON [PRIMARY]
- GO
复制代码
(2).用户Model的编写,这个Model直接与Sql表的结构一致。- public class Manager
- {
- /// <summary>
- /// 主键 MaxLength属性作用于字符串,不能用在int类型上
- /// </summary>
- [Key]
- public int Id { get; set; }
- /// <summary>
- /// 角色ID
- /// </summary>
- public int RoleId { get; set; }
- /// <summary>
- /// 用户名
- /// </summary>
- [Required]
- public String UserName { get; set; }
- /// <summary>
- /// 密码
- /// </summary>
- public String Password { get; set; }
- /// <summary>
- /// 头像
- /// </summary>
- public String Avatar { get; set; }
- /// <summary>
- /// 用户昵称
- /// </summary>
- public String NickName { get; set; }
- /// <summary>
- /// 手机号码
- /// </summary>
- public String Mobile { get; set; }
- /// <summary>
- /// 邮箱地址
- /// </summary>
- public String Email { get; set; }
- /// <summary>
- /// 登录次数
- /// </summary>
- public int? LoginCount { get; set; }
- /// <summary>
- /// 最后一次登录IP
- /// </summary>
- public String LoginLastIp { get; set; }
- /// <summary>
- /// 最后一次登录时间
- /// </summary>
- public DateTime? LoginLastTime { get; set; }
- /// <summary>
- /// 添加人
- /// </summary>
- [Required]
- public int AddManagerId { get; set; }
- /// <summary>
- /// 添加时间
- /// </summary>
- [Required]
- public DateTime AddTime { get; set; }
- /// <summary>
- /// 修改人
- /// </summary>
- public int? ModifyManagerId { get; set; }
- /// <summary>
- /// 修改时间
- /// </summary>
- [MaxLength(23)]
- public DateTime? ModifyTime { get; set; }
- /// <summary>
- /// 是否锁定
- /// </summary>
- [Required]
- public Boolean IsLock { get; set; }
- /// <summary>
- /// 是否删除
- /// </summary>
- [Required]
- public Boolean IsDelete { get; set; }
- /// <summary>
- /// 备注
- /// </summary>
- public String Remark { get; set; }
- }
复制代码
(3).用户View部分的编写
(3.1)视图View部分包括用户的增、删、改、查功能,还有对应的修改用户角色,修改用户密码。

(3.2)Create视图代码如下
 - @{ ViewData["Title"] = "新建用户"; }
- @model RegisterManagerView
- @section Scripts{
- @{ await Html.RenderPartialAsync("_ValidationScriptsPartial");}
- }
- <form action="/Manager/Create" method="post">
- @Html.AntiForgeryToken()
- <label asp-for="UserName">用户名</label>
- <input type="text" asp-for="UserName" name="UserName" placeholder="用户名">
- <span asp-validation-for="UserName" class="text-danger"></span>
- <label asp-for="Password">密码</label>
- <input type="password" asp-for="Password" name="Password" placeholder="密码" />
- <span asp-validation-for="Password" class="text-danger"></span>
- <label asp-for="ConfirmPassword">确认密码</label>
- <input type="password" asp-for="ConfirmPassword" name="ConfirmPassword" placeholder="确认密码" />
- <span asp-validation-for="ConfirmPassword" class="text-danger"></span>
- <label asp-for="Mobile">手机号</label>
- <input type="text" asp-for="Mobile" name="Mobile" placeholder="手机号">
- <span asp-validation-for="Mobile" class="text-danger"></span>
- <label asp-for="Email">Email</label>
- <input type="text" asp-for="Email" name="Email" placeholder="邮箱">
- <span asp-validation-for="Email" class="text-danger"></span>
- <label asp-for="Remark">介绍</label>
- <textarea name="Remark" asp-for="Remark" placeholder="相关介绍"></textarea>
- <button type="submit">确定</button>
- <button type="reset">重置</button>
- </form>
复制代码
(3.3)Edit视图代码如下
 - @{ ViewData["Title"] = "编辑用户"; }
- @model EditManagerView
- @section Scripts{
- @{ await Html.RenderPartialAsync("_ValidationScriptsPartial");}
- }
- <form action="/Manager/Edit" method="post">
- @Html.AntiForgeryToken()
- <label asp-for="UserName">用户名</label>
- <input type="text" asp-for="UserName" name="UserName" placeholder="用户名">
- <span asp-validation-for="UserName" class="text-danger"></span>
- <input type="hidden" asp-for="Id" />
- <label asp-for="Mobile">手机号</label>
- <input type="text" asp-for="Mobile" name="Mobile" placeholder="手机号">
- <span asp-validation-for="Mobile" class="text-danger"></span>
- <label asp-for="Email">Email</label>
- <input type="text" asp-for="Email" name="Email" placeholder="邮箱">
- <span asp-validation-for="Email" class="text-danger"></span>
- <label asp-for="Remark">介绍</label>
- <textarea name="Remark" asp-for="Remark" placeholder="相关介绍"></textarea>
- <button type="submit">确定</button>
- <button type="reset">重置</button>
- </form>
复制代码
(3.4)Index视图代码如下(列表页)
 - @using Humanizer;
- @using RjWebCms.Db;
- @model PaginatedList<PageManager>
- @{
- ViewData["Title"] = "用户列表";
- }
- @section Scripts{
- }
- @Html.AntiForgeryToken()
- <form asp-action="Index" method="get">
- <table>
- <tr><td><a asp-controller="Manager" asp-action="Create">添加</a></td></tr>
- <tr>
- <td>查询关键词:<input type="text" name="SearchString" value="@ViewData["CurrentFilter"]" /></td>
- <td><input type="submit" value="查询" /></td>
- <td><a asp-action="Index">Back</a></td>
- <td><a id="DelAll" name="DelAll">批量删除</a></td>
- </tr>
- </table>
- </form>
- <table class="table table-hover">
- <thead>
- <tr>
- <td>✔</td>
- <td><a asp-action="Index" asp-route-sortOrder="@ViewData["NameSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">用户名</a></td>
- <td>角色名</td>
- <td>手机号</td>
- <td><a asp-action="Index" asp-route-sortOrder="@ViewData["DateSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">时间</a></td>
- <td>操作</td>
- </tr>
- @foreach (var item in Model)
- {
- <tr>
- <td><input type="checkbox" class="done-checkbox" name="chk_ids" value="@item.Id"></td>
- <td>@item.UserName</td>
- <td>@item.RoleName</td>
- <td>@item.Mobile</td>
- <td>@item.AddTime</td>
- <td>
- <a asp-controller="Manager" asp-action="Details" asp-route-id="@item.Id">View</a>
- <a asp-action="Edit" asp-route-id="@item.Id">Edit</a>
- <a asp-action="ChangeRole" asp-route-id="@item.Id">ChangeRole</a>
- <a asp-action="ChangePass" asp-route-id="@item.Id">ChangePass</a>
- <a asp-controller="Manager" asp-action="Delete" asp-route-id="@item.Id">Delete</a>
- </td>
- </tr>
- }
- </thead>
- </table>
- @{
- var prevDisabled = !Model.HasPreviousPage ? "disabled" : "";
- var nextDisabled = !Model.HasNextPage ? "disabled" : ""; ;
- }
- <a asp-action="Index"
- asp-route-sortOrder="@ViewData["CurrentSort"]"
- asp-route-pageNumber="@(Model.PageIndex - 1)"
- asp-route-currentFilter="@ViewData["CurrentFilter"]"
- class="btn btn-default @prevDisabled">
- 上一页
- </a>
- <a asp-action="Index"
- asp-route-sortOrder="@ViewData["CurrentSort"]"
- asp-route-pageNumber="@(Model.PageIndex + 1)"
- asp-route-currentFilter="@ViewData["CurrentFilter"]"
- class="btn btn-default @nextDisabled">
- 下一页
- </a>
复制代码
(3.5)ChangePass视图代码
 - @model ChangePassView
- @section Scripts{
- @{ await Html.RenderPartialAsync("_ValidationScriptsPartial");}
- }
- <form action="/Manager/ChangePass" method="post">
- @Html.AntiForgeryToken()
- <label asp-for="OldPass">旧密码</label>
- <input type="hidden" asp-for="Id" />
- <input type="password" asp-for="OldPass" name="OldPass" placeholder="密码" />
- <span asp-validation-for="OldPass" class="text-danger"></span>
- <label asp-for="NewPass">新密码</label>
- <input type="password" asp-for="NewPass" name="NewPass" placeholder="密码" />
- <span asp-validation-for="NewPass" class="text-danger"></span>
- <label asp-for="ConfirmNewPass">确认新密码</label>
- <input type="password" asp-for="ConfirmNewPass" name="ConfirmNewPass" placeholder="确认密码" />
- <span asp-validation-for="ConfirmNewPass" class="text-danger"></span>
- <button type="submit">确定</button>
- <button type="reset">重置</button>
- </form>
复制代码
(3.6)ChangeRole视图代码
 - @using RjWebCms.Models;
- @{ ViewData["Title"] = "修改对应角色"; }
- @model ChangeUserRole
- <form action="/Manager/ChangeRole" method="post">
- @Html.AntiForgeryToken()
- <label asp-for="Id">选择对应角色</label>
- <input type="hidden" asp-for="Id" />
- @Html.DropDownList("ddl_RoleList", ViewBag.database as IEnumerable<SelectListItem>)
- <button type="submit">确定</button>
- <button type="reset">重置</button>
- </form>
复制代码
(4).用户Controller部分的实现- public class ManagerController : Controller{
- private readonly IManagerService _manager;
- private readonly IManagerRoleService _managerRoleService;
- private readonly AppDbContext _appDbContext;
- public ManagerController(IManagerService manager,IManagerRoleService managerRoleService, AppDbContext appDbContext){
- _manager = manager;
- _managerRoleService = managerRoleService;
- _appDbContext = appDbContext;
- }
- public async Task<IActionResult> Index(string sortOrder, string currentFilter, string searchString, int? pageNumber){
- ViewData["CurrentSort"] = sortOrder;
- ViewData["NameSortParm"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
- ViewData["DateSortParm"] = sortOrder == "Date" ? "date_desc" : "Date";
- if (searchString != null)
- {
- pageNumber = 1;
- }
- else
- {
- searchString = currentFilter;
- }
- #region 分页操作数据
- ViewData["CurrentFilter"] = searchString;
- var managers = from s in _appDbContext.Manager
- join t in _appDbContext.ManagerRole on s.RoleId equals t.Id
- select new PageManager{
- Id=s.Id,
- RoleId =s.RoleId,
- UserName = s.UserName,
- Email = s.Email,
- Mobile = s.Mobile,
- AddTime = s.AddTime,
- RoleName = t.RoleName};
- if (!string.IsNullOrEmpty(searchString))
- {
- managers = managers.Where(s => s.UserName.Contains(searchString));
- }
- switch (sortOrder)
- {
- case "name_desc":
- managers = managers.OrderByDescending(s => s.UserName);
- break;
- case "Date":
- managers = managers.OrderBy(s => s.AddTime);
- break;
- case "date_desc":
- managers = managers.OrderByDescending(s => s.AddTime);
- break;
- default:
- managers = managers.OrderBy(s => s.UserName);
- break;
- }
- #endregion
- int pageSize = 4;
- return View(await PaginatedList<PageManager>.CreateAsync(managers.AsNoTracking(), pageNumber ?? 1, pageSize));
- }
- [HttpGet]
- public IActionResult Create()
- {
- return View();
- }
- [HttpPost]
- [ValidateAntiForgeryToken]
- public async Task<IActionResult> Create(RegisterManagerView manager)
- {
- if (ModelState.IsValid)
- {
- Manager mUser = new Manager
- {
- UserName = manager.UserName,//但暂时用重写的方式来处理
- Password = AESEncryptHelper.Encode(manager.Password.Trim(), RjWebKeys.AesEncryptKeys), //对密码加密;
- Mobile = manager.Mobile,
- Email = manager.Email,
- Remark = manager.Remark
- };
- //此处可以用AutoMapper进行转换
- //因为AddManagerAsync的参数是Manager对象,而非RegisterManagerView对象
- //否则就需要重写一个AddManagerAsync(RegisterManagerView manager) 这样的方法
- var successful = await _manager.AddManagerAsync(mUser);
- if (successful)
- return RedirectToAction("Index");
- else
- return BadRequest("失败");
- }
- return View(manager);
- }
- [HttpGet]
- public async Task<IActionResult> Edit(int id)
- {
- if (string.IsNullOrEmpty(id.ToString()))
- return NotFound();
- var m = await _manager.FindManagerAsync(id);
- if (m == null)
- return NotFound();
- EditManagerView mView = new EditManagerView() {
- Id = id,
- UserName = m.UserName,
- //Password = AESEncryptHelper.Decode(m.Password,RjWebKeys.AesEncryptKeys), //解密密码
- //ConfirmPassword = AESEncryptHelper.Decode(m.Password, RjWebKeys.AesEncryptKeys), //解密密码
- Mobile = m.Mobile,
- Email = m.Email,
- Remark = m.Remark
- };
- return View(mView);
- }
- [HttpPost]
- public async Task<IActionResult> Edit(int id, EditManagerView editManager)
- {
- if (string.IsNullOrEmpty(id.ToString()))
- return NotFound();
- if (ModelState.IsValid)
- {
- try
- {
- //做个对象转换
- Manager mUser = new Manager {
- UserName = editManager.UserName,
- Mobile = editManager.Mobile,
- Email = editManager.Email,
- Remark = editManager.Remark
- };
- //因为UpdateManagerAysnc方法参数为完整Manger对象,所以要转换
- var result = await _manager.UpdateManagerAysnc(id, mUser);
- if(result)
- return RedirectToAction("Index");
- else
- return BadRequest("编辑失败");
- }
- catch (Exception ex)
- {
- return BadRequest("编辑失败");
- }
- }
- return View();
- }
- public async Task<IActionResult> Details(int id)
- {
- var item = await _manager.FindManagerAsync(id);
- return View(item);
- }
- public async Task<IActionResult> Delete(int id)
- {
- var result = await _manager.DeleteManagerAsync(id);
- if (result)
- return RedirectToAction("Index");
- else
- return Ok("删除失败!");
- }
- [HttpGet]
- public async Task<IActionResult> ChangePass(int id)
- {
- if (string.IsNullOrEmpty(id.ToString()))
- return NotFound();
- //密码框的初始化也可以省略
- var m = await _manager.FindManagerAsync(id);
- if (m == null)
- return NotFound();
- ChangePassView cpView = new ChangePassView {
- Id=id,
- OldPass = AESEncryptHelper.Decode(m.Password, RjWebKeys.AesEncryptKeys) //解密密码m.Password,
- };
- return View(cpView);
- }
- [HttpPost]
- [ValidateAntiForgeryToken]
- public async Task<IActionResult> ChangePass(int id,ChangePassView cheView)
- {
- if (string.IsNullOrEmpty(id.ToString()))
- return NotFound();
- if (ModelState.IsValid)
- {
- //ChangePass方法在ManagerService中,注意参数对象
- var successful = await _manager.ChangePass(id,cheView);
- if (successful)
- return RedirectToAction("Index");
- else
- return BadRequest("失败");
- }
- return View();
- }
- [HttpGet]
- public async Task<IActionResult> ChangeRole(int id)
- {
- //本Action调用后,要初始化下拉框的选择
- var user = await _manager.FindManagerAsync(id);
- if (user == null)
- return NotFound();
- #region 绑定类别下拉框
- var rolelist = await _managerRoleService.GetManagerRoleAsync();
- var roleItems = new List<SelectListItem>()
- {
- new SelectListItem(){ Value="0",Text="全部",Selected=true}
- };
- foreach (var role in rolelist)
- {
- SelectListItem item = new SelectListItem() { Value = role.Id.ToString(), Text = role.RoleName };
- roleItems.Add(item);
- }
- //遍历并选中(实现选中下拉框功能)
- foreach (SelectListItem item in roleItems)
- {
- if (item.Value == user.RoleId.ToString())
- item.Selected = true;
- }
- ViewBag.database = roleItems;
- #endregion
- return View();
- }
- [HttpPost]
- [ValidateAntiForgeryToken]
- public async Task<IActionResult> ChangeRole(int id ,ChangeUserRole user)
- {
- //修改用户所属角色
- if (string.IsNullOrEmpty(id.ToString()))
- return NotFound();
- #region 取下拉菜单值(RoleId)
- string strRoleId = Request.Form["ddl_RoleList"];
- if (!string.IsNullOrEmpty(strRoleId))
- user.RoleId = int.Parse(strRoleId);
- else
- user.RoleId = 0;
- #endregion
- if (ModelState.IsValid)
- {
- try
- {
- //ChangeRole方法在ManagerService中,注意其参数
- var result = await _manager.ChangeRole(id, user);
- if (result)
- return RedirectToAction("Index");
- else
- return BadRequest("编辑失败");
- }
- catch (Exception ex)
- {
- return BadRequest("编辑失败");
- }
- }
- return View();
- }
- #region 验证功能
- [HttpGet]
- public async Task<IActionResult> CheckUserName(string UserName)
- {
- //result=true,表示有这个用户名,说明验证失败,无法添加
- //那么return json 需要返回一个false
- bool result = await _manager.CheckUserName(UserName);
- return Json(!result); //返回结果必须是Json格式
- }
- [HttpGet]
- public async Task<IActionResult> CheckMobile(string Mobile)
- {
- //result=true,表示有这个手机号,说明验证失败,无法添加
- //那么return json 需要返回一个false
- bool result = await _manager.CheckMobile(Mobile);
- return Json(!result); //返回结果必须是Json格式
- }
- [HttpGet]
- public async Task<IActionResult> CheckEmail(string Email)
- {
- //result=true,表示有这个邮箱,说明验证失败,无法添加
- //那么return json 需要返回一个false
- bool result = await _manager.CheckEmail(Email);
- return Json(!result); //返回结果必须是Json格式
- }
- [HttpGet]
- public async Task<IActionResult> CheckOldPass(int id,string oldpass)
- {
- //result=true,表示有这个旧密码,说明验证失败,无法添加
- //那么return json 需要返回一个false
- string strPass = AESEncryptHelper.Encode(oldpass.Trim(), RjWebKeys.AesEncryptKeys); //对密码加密;
- bool result = await _manager.CheckOldPass(id,strPass);
- return Json(result); //返回结果必须是Json格式
- }
- #endregion
- }
复制代码
2.用户分配角色
分配角色在ChangeRole视图页面完成,注意阅读其对应代码;
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |