IE盒子

搜索
查看: 171|回复: 1

篇 (15)-Asp.Net Core入门实战-权限管理之用户创建与关联角 …

[复制链接]

3

主题

6

帖子

11

积分

新手上路

Rank: 1

积分
11
发表于 2023-1-18 07:12:34 | 显示全部楼层 |阅读模式
入门实战-权限管理之用户创建与关联角色(ViewModel再用与模型验证一)
在上个篇章中,讲了角色和菜单的关系(也就是给角色赋权),本章讲用户和给用户分派角色的功能。如果是小白,最好是仔细看我写的代码,因为关键代码处都有注解。建议将篇14和篇15阅读完毕再做演练,为防止单篇过长,我将其分成2篇来讲解。
用户与角色的处理逻辑是:(1).用户的增删改查;(2).给用户选一个所属角色。

  • 用户管理功能
    (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.checked == true) {
                    arrIds += ids.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="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视图页面完成,注意阅读其对应代码;
回复

使用道具 举报

1

主题

4

帖子

9

积分

新手上路

Rank: 1

积分
9
发表于 2025-6-15 15:59:49 | 显示全部楼层
我擦!我要沙发!
回复

使用道具 举报

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

本版积分规则

快速回复 返回顶部 返回列表