篇(15)-入门实战-权限管理之用户创建与关联角色(ViewModel再用与模型验证一 ...

打印 上一主题 下一主题

主题 903|帖子 903|积分 2709

篇(15)-Asp.Net Core入门实战-权限管理之用户创建与关联角色(ViewModel再用与模型验证一)
在上个篇章中,讲了角色和菜单的关系(也就是给角色赋权),本章讲用户和给用户分派角色的功能。如果是小白,最好是仔细看我写的代码,因为关键代码处都有注解。建议将篇14和篇15阅读完毕再做演练,为防止单篇过长,我将其分成2篇来讲解。
用户与角色的处理逻辑是:(1).用户的增删改查;(2).给用户选一个所属角色。
1.用户管理功能
(1).用户表(Sql库)的创建
  1. CREATE TABLE [dbo].[Manager](
  2. [Id] [int] IDENTITY(1,1) NOT NULL,
  3. [RoleId] [int] NOT NULL,
  4. [UserName] [varchar](32) NOT NULL,
  5. [Password] [varchar](128) NOT NULL,
  6. [Avatar] [varchar](256) NULL,
  7. [NickName] [varchar](32) NULL,
  8. [Mobile] [varchar](16) NULL,
  9. [Email] [varchar](128) NULL,
  10. [LoginCount] [int] NULL,
  11. [LoginLastIp] [varchar](64) NULL,
  12. [LoginLastTime] [datetime] NULL,
  13. [AddManagerId] [int] NOT NULL,
  14. [AddTime] [datetime] NOT NULL,
  15. [ModifyManagerId] [int] NULL,
  16. [ModifyTime] [datetime] NULL,
  17. [IsLock] [bit] NOT NULL,
  18. [IsDelete] [bit] NOT NULL,
  19. [Remark] [varchar](128) NULL,
  20. CONSTRAINT [PK_MANAGER] PRIMARY KEY NONCLUSTERED
  21. (
  22. [Id] ASC
  23. )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
  24. ) ON [PRIMARY]
  25. GO
复制代码
 
(2).用户Model的编写,这个Model直接与Sql表的结构一致。
  1. public class Manager
  2. {
  3. /// <summary>
  4. /// 主键 MaxLength属性作用于字符串,不能用在int类型上
  5. /// </summary>
  6. [Key]
  7. public int Id { get; set; }
  8. /// <summary>
  9. /// 角色ID
  10. /// </summary>
  11. public int RoleId { get; set; }
  12. /// <summary>
  13. /// 用户名
  14. /// </summary>
  15. [Required]
  16. public String UserName { get; set; }
  17. /// <summary>
  18. /// 密码
  19. /// </summary>
  20. public String Password { get; set; }
  21. /// <summary>
  22. /// 头像
  23. /// </summary>
  24. public String Avatar { get; set; }
  25. /// <summary>
  26. /// 用户昵称
  27. /// </summary>
  28. public String NickName { get; set; }
  29. /// <summary>
  30. /// 手机号码
  31. /// </summary>
  32. public String Mobile { get; set; }
  33. /// <summary>
  34. /// 邮箱地址
  35. /// </summary>
  36. public String Email { get; set; }
  37. /// <summary>
  38. /// 登录次数
  39. /// </summary>
  40. public int? LoginCount { get; set; }
  41. /// <summary>
  42. /// 最后一次登录IP
  43. /// </summary>
  44. public String LoginLastIp { get; set; }
  45. /// <summary>
  46. /// 最后一次登录时间
  47. /// </summary>
  48. public DateTime? LoginLastTime { get; set; }
  49. /// <summary>
  50. /// 添加人
  51. /// </summary>
  52. [Required]
  53. public int AddManagerId { get; set; }
  54. /// <summary>
  55. /// 添加时间
  56. /// </summary>
  57. [Required]
  58. public DateTime AddTime { get; set; }
  59. /// <summary>
  60. /// 修改人
  61. /// </summary>
  62. public int? ModifyManagerId { get; set; }
  63. /// <summary>
  64. /// 修改时间
  65. /// </summary>
  66. [MaxLength(23)]
  67. public DateTime? ModifyTime { get; set; }
  68. /// <summary>
  69. /// 是否锁定
  70. /// </summary>
  71. [Required]
  72. public Boolean IsLock { get; set; }
  73. /// <summary>
  74. /// 是否删除
  75. /// </summary>
  76. [Required]
  77. public Boolean IsDelete { get; set; }
  78. /// <summary>
  79. /// 备注
  80. /// </summary>
  81. public String Remark { get; set; }
  82. }
复制代码
 
(3).用户View部分的编写
(3.1)视图View部分包括用户的增、删、改、查功能,还有对应的修改用户角色,修改用户密码。

(3.2)Create视图代码如下
  1. @{ ViewData["Title"] = "新建用户"; }
  2. @model RegisterManagerView
  3. @section Scripts{
  4. @{ await Html.RenderPartialAsync("_ValidationScriptsPartial");}
  5. }
  6. <form action="/Manager/Create" method="post">
  7. @Html.AntiForgeryToken()
  8. <label asp-for="UserName">用户名</label>
  9. <input type="text" asp-for="UserName" name="UserName" placeholder="用户名">
  10. <span asp-validation-for="UserName" class="text-danger"></span>
  11. <label asp-for="Password">密码</label>
  12. <input type="password" asp-for="Password" name="Password" placeholder="密码" />
  13. <span asp-validation-for="Password" class="text-danger"></span>
  14. <label asp-for="ConfirmPassword">确认密码</label>
  15. <input type="password" asp-for="ConfirmPassword" name="ConfirmPassword" placeholder="确认密码" />
  16. <span asp-validation-for="ConfirmPassword" class="text-danger"></span>
  17. <label asp-for="Mobile">手机号</label>
  18. <input type="text" asp-for="Mobile" name="Mobile" placeholder="手机号">
  19. <span asp-validation-for="Mobile" class="text-danger"></span>
  20. <label asp-for="Email">Email</label>
  21. <input type="text" asp-for="Email" name="Email" placeholder="邮箱">
  22. <span asp-validation-for="Email" class="text-danger"></span>
  23. <label asp-for="Remark">介绍</label>
  24. <textarea name="Remark" asp-for="Remark" placeholder="相关介绍"></textarea>
  25. <button type="submit">确定</button>
  26. <button type="reset">重置</button>
  27. </form>
复制代码
 
(3.3)Edit视图代码如下
  1. @{ ViewData["Title"] = "编辑用户"; }
  2. @model EditManagerView
  3. @section Scripts{
  4. @{ await Html.RenderPartialAsync("_ValidationScriptsPartial");}
  5. }
  6. <form action="/Manager/Edit" method="post">
  7. @Html.AntiForgeryToken()
  8. <label asp-for="UserName">用户名</label>
  9. <input type="text" asp-for="UserName" name="UserName" placeholder="用户名">
  10. <span asp-validation-for="UserName" class="text-danger"></span>
  11. <input type="hidden" asp-for="Id" />
  12. <label asp-for="Mobile">手机号</label>
  13. <input type="text" asp-for="Mobile" name="Mobile" placeholder="手机号">
  14. <span asp-validation-for="Mobile" class="text-danger"></span>
  15. <label asp-for="Email">Email</label>
  16. <input type="text" asp-for="Email" name="Email" placeholder="邮箱">
  17. <span asp-validation-for="Email" class="text-danger"></span>
  18. <label asp-for="Remark">介绍</label>
  19. <textarea name="Remark" asp-for="Remark" placeholder="相关介绍"></textarea>
  20. <button type="submit">确定</button>
  21. <button type="reset">重置</button>
  22. </form>
复制代码
 
(3.4)Index视图代码如下(列表页)
  1. @using Humanizer;
  2. @using RjWebCms.Db;
  3. @model PaginatedList<PageManager>
  4. @{
  5. ViewData["Title"] = "用户列表";
  6. }
  7. @section Scripts{
  8. }
  9. @Html.AntiForgeryToken()
  10. <form asp-action="Index" method="get">
  11. <table>
  12. <tr><td><a asp-controller="Manager" asp-action="Create">添加</a></td></tr>
  13. <tr>
  14. <td>查询关键词:<input type="text" name="SearchString" value="@ViewData["CurrentFilter"]" /></td>
  15. <td><input type="submit" value="查询" /></td>
  16. <td><a asp-action="Index">Back</a></td>
  17. <td><a id="DelAll" name="DelAll">批量删除</a></td>
  18. </tr>
  19. </table>
  20. </form>
  21. <table class="table table-hover">
  22. <thead>
  23. <tr>
  24. <td>✔</td>
  25. <td><a asp-action="Index" asp-route-sortOrder="@ViewData["NameSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">用户名</a></td>
  26. <td>角色名</td>
  27. <td>手机号</td>
  28. <td><a asp-action="Index" asp-route-sortOrder="@ViewData["DateSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">时间</a></td>
  29. <td>操作</td>
  30. </tr>
  31. @foreach (var item in Model)
  32. {
  33. <tr>
  34. <td><input type="checkbox" class="done-checkbox" name="chk_ids" value="@item.Id"></td>
  35. <td>@item.UserName</td>
  36. <td>@item.RoleName</td>
  37. <td>@item.Mobile</td>
  38. <td>@item.AddTime</td>
  39. <td>
  40. <a asp-controller="Manager" asp-action="Details" asp-route-id="@item.Id">View</a>
  41. <a asp-action="Edit" asp-route-id="@item.Id">Edit</a>
  42. <a asp-action="ChangeRole" asp-route-id="@item.Id">ChangeRole</a>
  43. <a asp-action="ChangePass" asp-route-id="@item.Id">ChangePass</a>
  44. <a asp-controller="Manager" asp-action="Delete" asp-route-id="@item.Id">Delete</a>
  45. </td>
  46. </tr>
  47. }
  48. </thead>
  49. </table>
  50. @{
  51. var prevDisabled = !Model.HasPreviousPage ? "disabled" : "";
  52. var nextDisabled = !Model.HasNextPage ? "disabled" : ""; ;
  53. }
  54. <a asp-action="Index"
  55. asp-route-sortOrder="@ViewData["CurrentSort"]"
  56. asp-route-pageNumber="@(Model.PageIndex - 1)"
  57. asp-route-currentFilter="@ViewData["CurrentFilter"]"
  58. class="btn btn-default @prevDisabled">
  59. 上一页
  60. </a>
  61. <a asp-action="Index"
  62. asp-route-sortOrder="@ViewData["CurrentSort"]"
  63. asp-route-pageNumber="@(Model.PageIndex + 1)"
  64. asp-route-currentFilter="@ViewData["CurrentFilter"]"
  65. class="btn btn-default @nextDisabled">
  66. 下一页
  67. </a>
复制代码
 
(3.5)ChangePass视图代码
  1. @model ChangePassView
  2. @section Scripts{
  3. @{ await Html.RenderPartialAsync("_ValidationScriptsPartial");}
  4. }
  5. <form action="/Manager/ChangePass" method="post">
  6. @Html.AntiForgeryToken()
  7. <label asp-for="OldPass">旧密码</label>
  8. <input type="hidden" asp-for="Id" />
  9. <input type="password" asp-for="OldPass" name="OldPass" placeholder="密码" />
  10. <span asp-validation-for="OldPass" class="text-danger"></span>
  11. <label asp-for="NewPass">新密码</label>
  12. <input type="password" asp-for="NewPass" name="NewPass" placeholder="密码" />
  13. <span asp-validation-for="NewPass" class="text-danger"></span>
  14. <label asp-for="ConfirmNewPass">确认新密码</label>
  15. <input type="password" asp-for="ConfirmNewPass" name="ConfirmNewPass" placeholder="确认密码" />
  16. <span asp-validation-for="ConfirmNewPass" class="text-danger"></span>
  17. <button type="submit">确定</button>
  18. <button type="reset">重置</button>
  19. </form>
复制代码
 
(3.6)ChangeRole视图代码
  1. @using RjWebCms.Models;
  2. @{ ViewData["Title"] = "修改对应角色"; }
  3. @model ChangeUserRole
  4. <form action="/Manager/ChangeRole" method="post">
  5. @Html.AntiForgeryToken()
  6. <label asp-for="Id">选择对应角色</label>
  7. <input type="hidden" asp-for="Id" />
  8. @Html.DropDownList("ddl_RoleList", ViewBag.database as IEnumerable<SelectListItem>)
  9. <button type="submit">确定</button>
  10. <button type="reset">重置</button>
  11. </form>
复制代码
 
 
(4).用户Controller部分的实现
  1. public class ManagerController : Controller{
  2.   private readonly IManagerService _manager;
  3.   private readonly IManagerRoleService _managerRoleService;
  4.   private readonly AppDbContext _appDbContext;
  5.   public ManagerController(IManagerService manager,IManagerRoleService managerRoleService, AppDbContext appDbContext){
  6.     _manager = manager;
  7.     _managerRoleService = managerRoleService;
  8.     _appDbContext = appDbContext;
  9.   }
  10.   public async Task<IActionResult> Index(string sortOrder, string currentFilter, string searchString, int? pageNumber){
  11.     ViewData["CurrentSort"] = sortOrder;
  12.     ViewData["NameSortParm"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
  13.     ViewData["DateSortParm"] = sortOrder == "Date" ? "date_desc" : "Date";
  14.   if (searchString != null)
  15.   {
  16.     pageNumber = 1;
  17.   }
  18.   else
  19.   {
  20.     searchString = currentFilter;
  21.   }
  22. #region 分页操作数据
  23. ViewData["CurrentFilter"] = searchString;
  24. var managers = from s in _appDbContext.Manager
  25. join t in _appDbContext.ManagerRole on s.RoleId equals t.Id
  26. select new PageManager{
  27. Id=s.Id,
  28. RoleId =s.RoleId,
  29. UserName = s.UserName,
  30. Email = s.Email,
  31. Mobile = s.Mobile,
  32. AddTime = s.AddTime,
  33. RoleName = t.RoleName};
  34. if (!string.IsNullOrEmpty(searchString))
  35. {
  36. managers = managers.Where(s => s.UserName.Contains(searchString));
  37. }
  38. switch (sortOrder)
  39. {
  40. case "name_desc":
  41. managers = managers.OrderByDescending(s => s.UserName);
  42. break;
  43. case "Date":
  44. managers = managers.OrderBy(s => s.AddTime);
  45. break;
  46. case "date_desc":
  47. managers = managers.OrderByDescending(s => s.AddTime);
  48. break;
  49. default:
  50. managers = managers.OrderBy(s => s.UserName);
  51. break;
  52. }
  53. #endregion
  54. int pageSize = 4;
  55. return View(await PaginatedList<PageManager>.CreateAsync(managers.AsNoTracking(), pageNumber ?? 1, pageSize));
  56. }
  57. [HttpGet]
  58. public IActionResult Create()
  59. {
  60. return View();
  61. }
  62. [HttpPost]
  63. [ValidateAntiForgeryToken]
  64. public async Task<IActionResult> Create(RegisterManagerView manager)
  65. {
  66. if (ModelState.IsValid)
  67. {
  68. Manager mUser = new Manager
  69. {
  70. UserName = manager.UserName,//但暂时用重写的方式来处理
  71. Password = AESEncryptHelper.Encode(manager.Password.Trim(), RjWebKeys.AesEncryptKeys), //对密码加密;
  72. Mobile = manager.Mobile,
  73. Email = manager.Email,
  74. Remark = manager.Remark
  75. };
  76. //此处可以用AutoMapper进行转换
  77. //因为AddManagerAsync的参数是Manager对象,而非RegisterManagerView对象
  78. //否则就需要重写一个AddManagerAsync(RegisterManagerView manager) 这样的方法
  79. var successful = await _manager.AddManagerAsync(mUser);
  80. if (successful)
  81. return RedirectToAction("Index");
  82. else
  83. return BadRequest("失败");
  84. }
  85. return View(manager);
  86. }
  87. [HttpGet]
  88. public async Task<IActionResult> Edit(int id)
  89. {
  90. if (string.IsNullOrEmpty(id.ToString()))
  91. return NotFound();
  92. var m = await _manager.FindManagerAsync(id);
  93. if (m == null)
  94. return NotFound();
  95. EditManagerView mView = new EditManagerView() {
  96. Id = id,
  97. UserName = m.UserName,
  98. //Password = AESEncryptHelper.Decode(m.Password,RjWebKeys.AesEncryptKeys), //解密密码
  99. //ConfirmPassword = AESEncryptHelper.Decode(m.Password, RjWebKeys.AesEncryptKeys), //解密密码
  100. Mobile = m.Mobile,
  101. Email = m.Email,
  102. Remark = m.Remark
  103. };
  104. return View(mView);
  105. }
  106. [HttpPost]
  107. public async Task<IActionResult> Edit(int id, EditManagerView editManager)
  108. {
  109. if (string.IsNullOrEmpty(id.ToString()))
  110. return NotFound();
  111. if (ModelState.IsValid)
  112. {
  113. try
  114. {
  115. //做个对象转换
  116. Manager mUser = new Manager {
  117. UserName = editManager.UserName,
  118. Mobile = editManager.Mobile,
  119. Email = editManager.Email,
  120. Remark = editManager.Remark
  121. };
  122. //因为UpdateManagerAysnc方法参数为完整Manger对象,所以要转换
  123. var result = await _manager.UpdateManagerAysnc(id, mUser);
  124. if(result)
  125. return RedirectToAction("Index");
  126. else
  127. return BadRequest("编辑失败");
  128. }
  129. catch (Exception ex)
  130. {
  131. return BadRequest("编辑失败");
  132. }
  133. }
  134. return View();
  135. }
  136. public async Task<IActionResult> Details(int id)
  137. {
  138. var item = await _manager.FindManagerAsync(id);
  139. return View(item);
  140. }
  141. public async Task<IActionResult> Delete(int id)
  142. {
  143. var result = await _manager.DeleteManagerAsync(id);
  144. if (result)
  145. return RedirectToAction("Index");
  146. else
  147. return Ok("删除失败!");
  148. }
  149. [HttpGet]
  150. public async Task<IActionResult> ChangePass(int id)
  151. {
  152. if (string.IsNullOrEmpty(id.ToString()))
  153. return NotFound();
  154. //密码框的初始化也可以省略
  155. var m = await _manager.FindManagerAsync(id);
  156. if (m == null)
  157. return NotFound();
  158. ChangePassView cpView = new ChangePassView {
  159. Id=id,
  160. OldPass = AESEncryptHelper.Decode(m.Password, RjWebKeys.AesEncryptKeys) //解密密码m.Password,
  161. };
  162. return View(cpView);
  163. }
  164. [HttpPost]
  165. [ValidateAntiForgeryToken]
  166. public async Task<IActionResult> ChangePass(int id,ChangePassView cheView)
  167. {
  168. if (string.IsNullOrEmpty(id.ToString()))
  169. return NotFound();
  170. if (ModelState.IsValid)
  171. {
  172. //ChangePass方法在ManagerService中,注意参数对象
  173. var successful = await _manager.ChangePass(id,cheView);
  174. if (successful)
  175. return RedirectToAction("Index");
  176. else
  177. return BadRequest("失败");
  178. }
  179. return View();
  180. }
  181. [HttpGet]
  182. public async Task<IActionResult> ChangeRole(int id)
  183. {
  184. //本Action调用后,要初始化下拉框的选择
  185. var user = await _manager.FindManagerAsync(id);
  186. if (user == null)
  187. return NotFound();
  188. #region 绑定类别下拉框
  189. var rolelist = await _managerRoleService.GetManagerRoleAsync();
  190. var roleItems = new List<SelectListItem>()
  191. {
  192. new SelectListItem(){ Value="0",Text="全部",Selected=true}
  193. };
  194. foreach (var role in rolelist)
  195. {
  196. SelectListItem item = new SelectListItem() { Value = role.Id.ToString(), Text = role.RoleName };
  197. roleItems.Add(item);
  198. }
  199. //遍历并选中(实现选中下拉框功能)
  200. foreach (SelectListItem item in roleItems)
  201. {
  202. if (item.Value == user.RoleId.ToString())
  203. item.Selected = true;
  204. }
  205. ViewBag.database = roleItems;
  206. #endregion
  207. return View();
  208. }
  209. [HttpPost]
  210. [ValidateAntiForgeryToken]
  211. public async Task<IActionResult> ChangeRole(int id ,ChangeUserRole user)
  212. {
  213. //修改用户所属角色
  214. if (string.IsNullOrEmpty(id.ToString()))
  215. return NotFound();
  216. #region 取下拉菜单值(RoleId)
  217. string strRoleId = Request.Form["ddl_RoleList"];
  218. if (!string.IsNullOrEmpty(strRoleId))
  219. user.RoleId = int.Parse(strRoleId);
  220. else
  221. user.RoleId = 0;
  222. #endregion
  223. if (ModelState.IsValid)
  224. {
  225. try
  226. {
  227. //ChangeRole方法在ManagerService中,注意其参数
  228. var result = await _manager.ChangeRole(id, user);
  229. if (result)
  230. return RedirectToAction("Index");
  231. else
  232. return BadRequest("编辑失败");
  233. }
  234. catch (Exception ex)
  235. {
  236. return BadRequest("编辑失败");
  237. }
  238. }
  239. return View();
  240. }
  241. #region 验证功能
  242. [HttpGet]
  243. public async Task<IActionResult> CheckUserName(string UserName)
  244. {
  245. //result=true,表示有这个用户名,说明验证失败,无法添加
  246. //那么return json 需要返回一个false
  247. bool result = await _manager.CheckUserName(UserName);
  248. return Json(!result); //返回结果必须是Json格式
  249. }
  250. [HttpGet]
  251. public async Task<IActionResult> CheckMobile(string Mobile)
  252. {
  253. //result=true,表示有这个手机号,说明验证失败,无法添加
  254. //那么return json 需要返回一个false
  255. bool result = await _manager.CheckMobile(Mobile);
  256. return Json(!result); //返回结果必须是Json格式
  257. }
  258. [HttpGet]
  259. public async Task<IActionResult> CheckEmail(string Email)
  260. {
  261. //result=true,表示有这个邮箱,说明验证失败,无法添加
  262. //那么return json 需要返回一个false
  263. bool result = await _manager.CheckEmail(Email);
  264. return Json(!result); //返回结果必须是Json格式
  265. }
  266. [HttpGet]
  267. public async Task<IActionResult> CheckOldPass(int id,string oldpass)
  268. {
  269. //result=true,表示有这个旧密码,说明验证失败,无法添加
  270. //那么return json 需要返回一个false
  271. string strPass = AESEncryptHelper.Encode(oldpass.Trim(), RjWebKeys.AesEncryptKeys); //对密码加密;
  272. bool result = await _manager.CheckOldPass(id,strPass);
  273. return Json(result); //返回结果必须是Json格式
  274. }
  275. #endregion
  276. }
复制代码
 
2.用户分配角色
分配角色在ChangeRole视图页面完成,注意阅读其对应代码;

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

圆咕噜咕噜

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表