篇(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{ <script type="text/javascript" src="~/lib/jquery-validation/dist/jquery.validate.js"></script> <script type="text/javascript" src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script> @{ await Html.RenderPartialAsync("_ValidationScriptsPartial");} } <form action="/Manager/Create" method="post"> @Html.AntiForgeryToken() <div> <label asp-for="UserName">用戶名</label> <div> <input type="text" asp-for="UserName" name="UserName" placeholder="用戶名"> <span asp-validation-for="UserName" class="text-danger"></span> </div> </div> <div> <label asp-for="Password">密碼</label> <div> <input type="password" asp-for="Password" name="Password" placeholder="密碼" /> <span asp-validation-for="Password" class="text-danger"></span> </div> </div> <div> <label asp-for="ConfirmPassword">確認密碼</label> <div> <input type="password" asp-for="ConfirmPassword" name="ConfirmPassword" placeholder="確認密碼" /> <span asp-validation-for="ConfirmPassword" class="text-danger"></span> </div> </div> <div> <label asp-for="Mobile">手機號</label> <div> <input type="text" asp-for="Mobile" name="Mobile" placeholder="手機號"> <span asp-validation-for="Mobile" class="text-danger"></span> </div> </div> <div> <label asp-for="Email">Email</label> <div> <input type="text" asp-for="Email" name="Email" placeholder="郵箱"> <span asp-validation-for="Email" class="text-danger"></span> </div> </div> <div> <label asp-for="Remark">介紹</label> <div> <textarea name="Remark" asp-for="Remark" placeholder="相關介紹"></textarea> </div> </div> <div> <div> <button type="submit">確定</button> <button type="reset">重置</button> </div> </div> </form>
(3.3)Edit視圖代碼如下

@{ ViewData["Title"] = "編輯用戶"; } @model EditManagerView @section Scripts{ <script type="text/javascript" src="~/lib/jquery-validation/dist/jquery.validate.js"></script> <script type="text/javascript" src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script> @{ await Html.RenderPartialAsync("_ValidationScriptsPartial");} } <form action="/Manager/Edit" method="post"> @Html.AntiForgeryToken() <div> <label asp-for="UserName">用戶名</label> <div> <input type="text" asp-for="UserName" name="UserName" placeholder="用戶名"> <span asp-validation-for="UserName" class="text-danger"></span> <input type="hidden" asp-for="Id" /> </div> </div> <div> <label asp-for="Mobile">手機號</label> <div> <input type="text" asp-for="Mobile" name="Mobile" placeholder="手機號"> <span asp-validation-for="Mobile" class="text-danger"></span> </div> </div> <div> <label asp-for="Email">Email</label> <div> <input type="text" asp-for="Email" name="Email" placeholder="郵箱"> <span asp-validation-for="Email" class="text-danger"></span> </div> </div> <div> <label asp-for="Remark">介紹</label> <div> <textarea name="Remark" asp-for="Remark" placeholder="相關介紹"></textarea> </div> </div> <div> <div> <button type="submit">確定</button> <button type="reset">重置</button> </div> </div> </form>
(3.4)Index視圖代碼如下(串列頁)

@using Humanizer; @using RjWebCms.Db; @model PaginatedList<PageManager> @{ ViewData["Title"] = "用戶串列"; } @section Scripts{ <script src="~/js/jquery-3.6.1.min.js"></script> <script type="text/javascript"> function DelAll() { var ids = document.getElementsByName("#chk_ids"); var arrIds = ""; var n = 0; for (var i = 0; i < ids.length; i++) { if (ids[i].checked == true) { arrIds += ids[i].value + ","; n++; } } if (n == 0) { alert("請選擇要洗掉的資訊"); return; } arrIds = arrids.substr(0, arrIds.length - 1); // if (confirm("確定要全部洗掉選擇用戶嗎")) { $.ajax({ type: "post", url: "/Manager/DeleteAll", data: { ids: arrIds }, success: function (data, state) { alert('洗掉成功!'); window.location.href = ""; }, error: function (data, state) { alert('洗掉失敗'); } }); } } </script> } <div class="panel panel-default todo-panel"> @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> <div class="panel-footer add-item-form"> <!-- TODO: Add item form --> </div> </div>
(3.5)ChangePass視圖代碼

@model ChangePassView @section Scripts{ <script type="text/javascript" src="~/lib/jquery-validation/dist/jquery.validate.js"></script> <script type="text/javascript" src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script> @{ await Html.RenderPartialAsync("_ValidationScriptsPartial");} } <form action="/Manager/ChangePass" method="post"> @Html.AntiForgeryToken() <div> <label asp-for="OldPass">舊密碼</label> <input type="hidden" asp-for="Id" /> <div> <input type="password" asp-for="OldPass" name="OldPass" placeholder="密碼" /> <span asp-validation-for="OldPass" class="text-danger"></span> </div> </div> <div> <label asp-for="NewPass">新密碼</label> <div> <input type="password" asp-for="NewPass" name="NewPass" placeholder="密碼" /> <span asp-validation-for="NewPass" class="text-danger"></span> </div> </div> <div> <label asp-for="ConfirmNewPass">確認新密碼</label> <div> <input type="password" asp-for="ConfirmNewPass" name="ConfirmNewPass" placeholder="確認密碼" /> <span asp-validation-for="ConfirmNewPass" class="text-danger"></span> </div> </div> <div> <div> <button type="submit">確定</button> <button type="reset">重置</button> </div> </div> </form>
(3.6)ChangeRole視圖代碼

@using RjWebCms.Models; @{ ViewData["Title"] = "修改對應角色"; } @model ChangeUserRole <form action="/Manager/ChangeRole" method="post"> @Html.AntiForgeryToken() <div> <label asp-for="Id">選擇對應角色</label> <input type="hidden" asp-for="Id" /> <div> @Html.DropDownList("ddl_RoleList", ViewBag.database as IEnumerable<SelectListItem>) </div> </div> <div> <div> <button type="submit">確定</button> <button type="reset">重置</button> </div> </div> </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=https://www.cnblogs.com/mushaobai/p/"0",Text="全部",Selected=true} }; foreach (var role in rolelist) { SelectListItem item = new SelectListItem() { Value = https://www.cnblogs.com/mushaobai/p/role.Id.ToString(), Text = role.RoleName }; roleItems.Add(item); } //遍歷并選中(實作選中下拉框功能) foreach (SelectListItem item in roleItems) { if (item.Value =https://www.cnblogs.com/mushaobai/p/= 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視圖頁面完成,注意閱讀其對應代碼;
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/536163.html
標籤:.NET Core
