冯 海

一个程序新人菜鸟的日记,希望大家多多关照。QQ:32316131

ASP.NET Identity教程三:(用户授权2)角色管理

1.  添加角色

角色管理的第一步,就是先创建一个角色,然后基于该角色可以进行后面的授权操作。在 ASP.NET Identity 中,对角色的管理非常简单,只要配置好 RoleManager,就可以从OWIN上下文中获取到RoleManager,然后执行相应的CRUD操作即可。

1.1 编写 AddRoleViewModel

在 IdentityRole 中,只有一个 Name 字段可用,所以我们在 AddRoleViewModel中,也只有一个 Name 属性。

在“ViewModels”文件夹中添加一个名称为“AddRoleViewModel.cs”的类文件,然后编写如下代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;

namespace jsdhh2.ViewModels
{
	public class AddRoleViewModel
	{
		[Required]
		[StringLength(20)]
		[Display(Name = "角色名称")]
		public string Name { get; set; }
	}
}

  

3.2. 编写 Add 方法

在“RoleController”控制器中编写 2 个 Add()方法,一个是 Get,一个是 Post。如下
代码:

/// <summary>
		/// 添加角色
		/// </summary>
		/// <returns></returns>
		[HttpGet]
		public ActionResult Add()
		{
			return View();
		}

		/// <summary>
		/// 添加角色
		/// </summary>
		/// <param name="model"></param>
		/// <returns></returns>
		[HttpPost]
		[ValidateAntiForgeryToken]
		public async Task<ActionResult> Add(AddRoleViewModel model)
		{
			if (ModelState.IsValid)
			{
				var result = await RoleManager.CreateAsync(new Models.Role(model.Name));
				if (result.Succeeded)
				{
					return RedirectToAction("List");
				}
				AddErrors(result);
			}
			return View();
		}

  使用 RoleManager.CreateAsync()异步方法,就可以添加角色名称到数据库中。

 

3.23.3. 编写 Add 视图:Views”“Role”文件夹中添加一个名称为“Add.cshtml”视图,然后编写如下代码

@model jsdhh2.ViewModels.AddRoleViewModel
@{
	ViewBag.Title = "添加角色";
}

@using (Html.BeginForm("Add", "Role", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
	@Html.AntiForgeryToken()
	<h4>添加角色。</h4>
	<hr />
	@Html.ValidationSummary("", new { @class = "text-danger" })
	<div class="form-group">
		@Html.LabelFor(m => m.Name, new { @class = "col-md-2 control-label" })
		<div class="col-md-10">
			@Html.TextBoxFor(m => m.Name, new { @class = "form-control" })
		</div>
	</div>
	<div class="form-group">
		<div class="col-md-offset-2 col-md-10">
			<input type="submit" class="btn btn-default" value="保存" />
		</div>
	</div>
}

  

上面的 ViewModel、方法和视图都编写完成之后,就可以运行 Add()方法和视图了,效果如图 8-5 所示

我的执行错误,提示了code first.呵,可以将原数据库删除,重新执行就可以。

未找到视图“List”或其母版视图,或没有视图引擎支持搜索的位置。搜索了以下位置: 
~/Views/Role/List.aspx
~/Views/Role/List.ascx
~/Views/Shared/List.aspx
~/Views/Shared/List.ascx
~/Views/Role/List.cshtml
~/Views/Role/List.vbhtml
~/Views/Shared/List.cshtml
~/Views/Shared/List.vbhtml

这是正常的,我们没有LIST视图。

可我们查看数据库,发现已正成的注入数据。

 

当角色添加成功后,就会转到 Role/List 页面,由于我们还没有编写 List()方法和视图,所以图 8-7 是访问不到的,也就出现了 HTTP 404 错误,但是有一点可以肯定,我们的角色名称添加成功了。

看到了3个字段,其中Discriminator字段是在添加角色名称时出现的。

4. 角色列表

现在我们来创建角色列表,用来显示所有添加的角色名称。

4.1. 编写 List 方法

在“RoleController”控制器中编写一个带有 HttpGet 的 List()方法,用于显示所有的角色名称。如下代码:

 

/// <summary>
/// 所有角色名称
/// </summary>
/// <returns></returns>
[HttpGet]
public ActionResult List()
{
var roleList = RoleManager.Roles.ToList();
return View(roleList);
}

  

在 List()方法中使用了 RoleManager.Roles.ToList()来获取所有的角色信息。这里没有使用 ViewModel,直接使用了 Yidosoft.Identity.Models.Role 作为 Model。

 4.2. 编写 List 视图:

在“Views”“Role”文件夹中添加“List.cshtml”视图,并编写如下代码

@model IEnumerable<Yidosoft.Identity.Models.Role>
@{
	ViewBag.Title = "角色列表";
}

<h4>角色列表</h4>

<p>
	@Html.ActionLink("添加角色", "Add")
</p>
<table class="table">
	<thead>
		<tr>
			<th>角色名称</th>
		</tr>
	</thead>
	<tbody>
		@foreach (var role in Model)
		{
			<tr>
				<td>@Html.DisplayFor(m => role.Name)</td>
				<td>
					@Html.ActionLink("编辑", "Edit", new { id = role.Id })
					@Html.ActionLink("删除", "Del", new { id = role.Id })
					@Html.ActionLink("添加用户", "UserToRole", new { id = role.Id })
					@Html.ActionLink("查看用户", "ViewRoleUser", new { id = role.Id })
				</td>
			</tr>
		}
	</tbody>
</table>

  

这里使用了 table 来显示角色列表,并且还添加了编辑、删除和添加角色链接,方便在角色列表中操作。现在运行一下,并刷新图 8-7 的页面,如图 8-9 所示:

在图 8-9 中已经将之前添加的角色名称显示出来了。点击此页面上的“添加角色”就可以继续添加其它角色名称。

5.  编辑角色

点击“编辑”链接就可以转到编辑页面对当前角色进行编辑,也就是修改角色的名称。

5.1. 编写 EditRoleViewModel

在“ViewModels”文件夹中添加“EditRoleViewModel.cs”类文件,并编写如下代码:

using System.ComponentModel.DataAnnotations;

namespace jsdhh2.ViewModels
{
	public class EditRoleViewModel
	{
		[Required]
		[StringLength(20)]
		[Display(Name = "角色名称")]
		public string Name { get; set; }
	}
}

  编辑角色时,只是对角色名称进行修改。

2. 编写 Edit 方法

使用 Edit()方法执行角色名称的编辑操作。在“RoleController”控制器中编写两个Edit()方法,一个带有 HttpGet 特性,一个带有 HttpPost 特性。如下代码:

[HttpGet]
		public ActionResult Edit(string id)
		{
			if (string.IsNullOrEmpty(id))
			{
				return new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest);
			}
			Models.Role role = RoleManager.FindById(id);
			if (role == null)
			{
				return HttpNotFound();
			}
			var editModel = new EditRoleViewModel()
			{
				Name = role.Name
			};
			return View(editModel);
		}

		/// <summary>
		/// 编辑角色
		/// </summary>
		/// <param name="id"></param>
		/// <param name="model"></param>
		/// <returns></returns>
		[HttpPost]
		[ValidateAntiForgeryToken]
		public async Task<ActionResult> Edit(string id, EditRoleViewModel model)
		{
			if (ModelState.IsValid && !string.IsNullOrEmpty(id))
			{
				var role = RoleManager.FindById(id);
				role.Name = model.Name;
				var result = await RoleManager.UpdateAsync(role);
				if (result.Succeeded)
				{
					return RedirectToAction("List");
				}
				AddErrors(result);
			}
			return View(model);
		}

  

对于 HttpGet 的 Edit()方法,会根据 URL 参数上的 id 值获取当前表单数据。对于HttpPost 的 Edit()方法,则可以将修改后的表单数据提交到服务器上。

5.3. 编写 Edit 视图

现在添加对应于 Edit()方法的默认视图 Edit.cshtml。在“Views”“Role”文件夹中添加 Edit.cshtml 视图,并编写如下代码

@model jsdhh2.ViewModels.EditRoleViewModel
@{
	ViewBag.Title = "编辑角色";
}

@using (Html.BeginForm("Edit", "Role", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
	@Html.AntiForgeryToken()
	<h4>编辑角色。</h4>
	<hr />
	@Html.ValidationSummary("", new { @class = "text-danger" })
	<div class="form-group">
		@Html.LabelFor(m => m.Name, new { @class = "col-md-2 control-label" })
		<div class="col-md-10">
			@Html.TextBoxFor(m => m.Name, new { @class = "form-control" })
		</div>
	</div>
	<div class="form-group">
		<div class="col-md-offset-2 col-md-10">
			<input type="submit" class="btn btn-default" value="提交" />
		</div>
	</div>
}

 将 EidtRoleViewModel、Edit()方法和 Edit 视图的代码编写完成之后,就可以运行一下结果。在图 8-9 中点击“编辑”链接,如图 8-10 所示:

 

可见,角色名称已经修改成功了

6. 删除角色

删除角色是指将角色从数据库中删除,由于目前为止还没有将用户关联到角色,所以可以直接将角色删除掉,如果角色已关联到用户,则需要先解除关联,再删除角色。

6.1. 编写 Delete 方法

这里我们不使用 ViewModel 和视图来删除角色,直接在角色列表上删除,删除完成后再返回到角色列表上。

在“RoleController”控制器中编写 Del()方法,用于完成删除操作。如下代码:

/// <summary>
		/// 删除角色
		/// </summary>
		/// <param name="id"></param>
		/// <returns></returns>
		[HttpGet]
		public async Task<ActionResult> Del(string id)
		{
			if (string.IsNullOrEmpty(id))
			{
				return new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest);
			}
			var role = RoleManager.FindById(id);
			if (role == null)
			{
				return HttpNotFound();
			}
			var result = await RoleManager.DeleteAsync(role);
			if (!result.Succeeded)
			{
				AddErrors(result);
			}
			return RedirectToAction("List");
		}

  

删除角色时,需要提供一个角色的 id 值,然后就可以使用
RoleManager.DeleteAsync()就可以删除角色了。删除角色只编写一个带有 HttpGet特性的 Del()方法即可。现在运行一下,并打开 Role/List 页面。如图 8-13 所示:

 

可见,当点击“删除”链接之后,直接又返回到了 List 页面,并且之前的角色给删除掉了,在数据库中也不存在了。

可是一点就删了,乱一误点了哩?

	@Html.ActionLink("删除", "Del", new { id = role.Id }, new { @class = "btn btn-warning", onclick = "return confirm('你确定要删除吗?')" })

  在Del链接那,加上一个弹窗即可。

7.  向角色添加用户

角色的最大功能就是能与用户关联,使关联到的用户具有同样的权限,这样我们在授予权限时,只给角色授权即可。

7.1. 添加链接

我们还是在角色列表中操作向角色添加用户,因此,需要添加一个链接,并需要
传递角色 Id 参数。
打开“Views”“Role”中的“List.cshtml”视图,然后添加如下代码:

<td>@Html.DisplayFor(m => role.Name)</td>
<td>
@Html.ActionLink("编辑", "Edit", new { id = role.Id })
@Html.ActionLink("删除", "Del", new { id = role.Id })
@Html.ActionLink("添加用户", "UserToRole", new { id = role.

 

在表格中添加了“添加用户”的链接,使用的操作方法是 UserToRole。然后在每个角色名称行的后面,都有一个“添加用户”的链接,点击该链接就可以给当前角色添加用户。

.7.2. 编写 UserToRole 方法

由于在操作角色用户时,需要在“RoleController”控制器中使用 UserManager,所以需要编写如下代码:

private UserManager _userManager;
public UserManager UserManager
{
get
{
return _userManager ??
HttpContext.GetOwinContext().GetUserManager<UserManager>();
}
private set
{
_userManager = value;
}
}

  在“RoleController”控制器中编写 UserToRole()方法的代码如下:

	/// 用户到角色列表
		/// </summary>
		/// <param name="id"></param>
		/// <returns></returns>
		[HttpGet]
		public ActionResult UserToRole(string id)
		{
			if (string.IsNullOrWhiteSpace(id))
			{
				return new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest);
			}
			var role = RoleManager.FindById(id);
			ViewBag.RoleName = role.Name;
			ViewBag.RoleId = id;
			if (role == null)
			{
				return HttpNotFound();
			}
			var memberIDs = role.Users.Select(x => x.UserId).ToArray();
			var members = UserManager.Users.Where(x => memberIDs.Any(y => y == x.Id));
			var membersNo = UserManager.Users.Except(members);
			return View(membersNo);
		}

在此方法中,使用了 role.Users 获取该角色中已经关联到的所有用户数据。然后再使用 UserManager.Users.Except()得到没有关联到角色的所有用户列表,这样我

们就可以执行添加用户操作,将没有关联到角色的用户添加到角色中。对于已经关联过的用户,将不再显示。

7.3. 编写 UserToRole 视图

在 UserToRole 视图中,以列表的形式将未添加到角色的用户显示出来。在“Views”“Role”文件夹中添加“UserToRole.cshtml”视图,并编写如下代码:

@model IEnumerable<jsdhh2.Models.User>
@{
	ViewBag.Title = "角色关联用户";
}

<h4>给 @ViewBag.RoleName 添加用户</h4>
<p>
	@Html.ActionLink("角色列表", "List")
</p>
<table class="table">
	<thead>
		<tr>
			<th>用户名</th>
			<th>电子邮件</th>
			<th>QQ号码</th>
			<th>微信号码</th>
		</tr>
	</thead>
	<tbody>
		@foreach (var user in Model)
		{
			<tr>
				<td>@Html.DisplayFor(m => user.UserName)</td>
				<td>@Html.DisplayFor(m => user.Email)</td>
				<td>@Html.DisplayFor(m => user.QQ)</td>
				<td>@Html.DisplayFor(m => user.PhoneNumber)</td>
				<td>
					@Html.ActionLink("添加到角色", "AddToRole", new { userId = user.Id, roleId = ViewBag.RoleId, roleName = ViewBag.RoleName })
				</td>
			</tr>
		}
	</tbody>
</table>

 

了操作方法和视图,就可以运行了,先看一下效果。打开 Role/List 页面,如图8-15 所示,然后点击“添加用户”连接,如图 8-16 所示:

在图 8-16 中已经看到可以添加到“创建权限”角色的所有用户,点击后面的“添加到用户”按钮,就可以实现将当前用户添加到角色中。

 

7.4. 编写 AddToRole 方法

在图 8-16 中点击“添加到角色”会执行 AddToRole()方法,从而实现将用户添加到角色的操作

	/// <summary>
		/// 添加用户到角色
		/// </summary>
		/// <param name="userId"></param>
		/// <param name="roleName"></param>
		/// <param name="roleId"></param>
		/// <returns></returns>
		public ActionResult AddToRole(string userId, string roleName, string roleId)
		{
			if (!string.IsNullOrWhiteSpace(userId) && !string.IsNullOrWhiteSpace(roleName))
			{
				UserManager.AddToRole(userId, roleName);
			}
			return RedirectToAction("UserToRole", new { id = roleId });
		}

 

在 ASP.NET Identity 中,只需要使用 UserManager.AddToRole()方法,提供 UserId和 RoleName 的值,就可以很容易的实现将用户与角色关联起来。此操作不需要视图,因为操作完成后直接就返回到 UserToRole 操作上了。现在编码都完成了,看一下效果,在图 8-16 中将“001@yidosoft.cn”用户添加到“创建权限”角色。如图 8-17 所示:

 

 

当将某个用户添加到角色之后,在图 8-17 中就看不到了。能看到的都是还没有添加到角色的用户。在数据库中,用户与角色的关联是存储在“AspNetUserRoles”表中的,现在我们查
看一下,如图 8-18 所示:

 

 

从图 8-18 上看,在“AspNetUserRoles”表中,只存储了 UserId 和 RoleId,这样就存在关联了。

8. 查看角色用户

在图 8-17 中添加用户到角色之后,我们怎么能看到这些用户呢?我们现在就实现这个功能,使我们能清楚的看到某个角色已经关联了几个用户

.1. 添加链接

同样,我们也需要在“List.cshtml”视图中添加一个“查看用户”的链接。如下代码

@Html.ActionLink("查看用户", "ViewRoleUser", new { id = role.Id }, new { @class = "btn btn-success" })

  8.2. 编写 ViewRoleUser 方法

在“RoleController”控制器中添加 ViewRoleUser()方法,并编写如下代码:

	/// 查看角色中的用户
		/// </summary>
		/// <param name="id"></param>
		/// <returns></returns>
		public ActionResult ViewRoleUser(string id)
		{
			if (string.IsNullOrWhiteSpace(id))
			{
				return new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest);
			}
			var role = RoleManager.FindById(id);
			ViewBag.RoleName = role.Name;
			var memberIDs = role.Users.Select(x => x.UserId).ToArray();
			var members = UserManager.Users.Where(x => memberIDs.Any(y => y == x.Id));
			return View(members);
		}

  

使用 UserManager.Users.Where()方法将所有与当前角色关联的用户过滤出来。

8.3. 编写 ViewRoleUser 视图

在“Views”“Role”文件夹中添加“ViewRoleUser.cshtml”视图,并编写如下代码:

@model IEnumerable<jsdhh2.Models.User>
@{
	ViewBag.Title = "角色关联的用户";
}

<h4>查看 @ViewBag.RoleName 中的用户</h4>
<p>
	@Html.ActionLink("角色列表", "List")
</p>
<table class="table">
	<thead>
		<tr>
			<th>用户名</th>
			<th>电子邮件</th>
			<th>QQ号码</th>
			<th>微信号码</th>
		</tr>
	</thead>
	<tbody>
		@foreach (var user in Model)
		{
			<tr>
				<td>@Html.DisplayFor(m => user.UserName)</td>
				<td>@Html.DisplayFor(m => user.Email)</td>
				<td>@Html.DisplayFor(m => user.QQNumber)</td>
				<td>@Html.DisplayFor(m => user.WechatNumber)</td>
				<td>
					@Html.ActionLink("移除用户", "RemoveRoleUser", new { roleName = ViewBag.RoleName, userId = user.Id })
				</td>
			</tr>
		}
	</tbody>
</table>

 

现在运行一下效果,在图 8-19 中点击“查看用户”,如图 8-20 所示:

9  角色授权

在上面关于角色的相关操作已经完成了,现在我们就可以使用角色授权了,还拿前面的“TestAuthorizeController”控制器作为例子。如下代码:

[Authorize(Roles ="创建权限")]
public ActionResult Index()
{
return View();
}
[AllowAnonymous]
public ActionResult Home()
{
return View();
}
}

  

在此代码中,给 Index()方法使用了:[Authorize(Roles ="创建权限")]
来授予权限,这样对于 Index()方法,只有“创建权限”角色中的用户可以访问,现在使用“003@yidosoft.cn”访问一下,如图 8-21 所示:

可见,直接转到了登录页面,表示没有权限访问。现在我们将“003@yidosoft.cn”用户添加到“创建权限”角色,如图 8-22 所示:

然后再访问“/TestAuthorize/Index”,如图 8-23 所示:再次访问就看见了。

可见,已经可以正常访问了。使用角色授权,我们只需要将角色规划好,然后在角色中添加用户就可以了。这样不但易于维护,使用起来也比较方便。

10. 移除用户

移除用户是指将指定的用户从某个角色中移除,移除后该用户就再具有角色的权限。

我们在 8.8 节中的“查看角色用户”列表中添加移除功能,在“ViewRoleUser.cshtml”视图中添加一个“移除用户”的链接,点击之后将该用户从角色中移除掉。代码如

@Html.ActionLink("移除用户", "RemoveRoleUser", new
{ roleName=ViewBag.RoleName, userId = user.Id })

  

“创建权限”角色中共有 2 个用户,我们可以点击每个用户后面的“移除用户”链接将用户从该角色中移除,也就是取消角色与用户的关联。

现在编写移除用户的逻辑,在“RoleController”控制器中,编写一个
“RemoveRoleUser()”方法,使用 HttpGet 请求,代码如下:

/// <param name="userId"></param>
		/// <returns></returns>
		[HttpGet]
		public ActionResult RemoveRoleUser(string roleName, string userId)
		{
			if (string.IsNullOrWhiteSpace(roleName) && string.IsNullOrWhiteSpace(userId))
			{
				return new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest);
			}
			var result = UserManager.RemoveFromRole(userId, roleName);
			var role = RoleManager.FindByName(roleName);
			if (!result.Succeeded)
			{
				return View("Error");
			}
			return RedirectToAction("ViewRoleUser", new { id = role.Id });
		}

  

在此代码中,使用了 UserManager.RemoveFromRole()将指定的用户从指定的角色中移除掉。移除成功后,直接又转到了“ViewRoleUser()”操作方法上。在图 8-24 中将“001@yidosoft.cn”用户移除掉,点击“移除用户”链接,

当点击过某个用户的“移除用户”之后,就会在图 8-25 中消失,表示与指定的角色解除了关联。至此,我们已经完成了 ASP.NET Identity 中的基本配置、用户管理、角色管理和
授权,这也是 ASP.NET Identity 的核心功能,也是在网站中最常用的功能,这里只是讲解了如何使用 ASP.NET Identity 的相关 API 去完成相应的功能,至于更多的功能,只需要按此方法举一反三就可以轻易的实现,方法很重要。

 

posted @ 2017-05-15 20:57  秋天来了哟  阅读(329)  评论(0编辑  收藏  举报
认识就是缘份,愿天下人都快乐!
QQ: 32316131
Email: 32316131@qq.com