角色是给用户分配了访问指定资源的权限,保护系统的安全性。
一个用户(User)可能会有多种角色(Role)
微软官方关于角色的管理的描述以及具体解决方案
仔细看看,描述的比较详细了
1.在db数据库中,添加role数据表:分配用户具有的角色
CREATE TABLE [dbo].[role] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[UserId] INT NOT NULL,
[Role] VARCHAR (50) NOT NULL,
PRIMARY KEY CLUSTERED ([Id] ASC),
FOREIGN KEY ([UserId]) REFERENCES [dbo].[user] ([Id])
);
添加测试数据:
更新EF的edmx文件.
2.启用角色管理,以及使用自定义的 Role Management Providers
微软官方Role Management Providers的说明
在web.config配置文件中,添加roleManager节点:
<system.web>
<!--配置authentication节点:拒绝匿名用户访问(相对于整个Web应用程序)
loginUrl:用户如果没有登录,则跳转到登录页面
-->
<authentication mode="Forms">
<forms loginUrl="~/Account/Login"></forms>
</authentication>
<!--启用角色管理-->
<roleManager defaultProvider="myRolePrv" enabled="true">
<providers>
<clear/>
<add name="myRolePrv" type="AuthenticationDemo.MyRoleProvider"/>
</providers>
</roleManager>
<compilation debug="true" targetFramework="4.5.2" />
<httpRuntime targetFramework="4.5.2" />
</system.web>
使用defaultProvider节点配置Provider
添加自定义的角色管理提供类MyRoleProvider:
需要继承RoleProvider抽象类,实现一些抽象方法
在当前项目下直接添加:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using AuthenticationDemo.Models;
namespace AuthenticationDemo
{
public class MyRoleProvider : RoleProvider
{
public override string ApplicationName
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public override void AddUsersToRoles(string[] usernames, string[] roleNames)
{
throw new NotImplementedException();
}
public override void CreateRole(string roleName)
{
throw new NotImplementedException();
}
public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
{
throw new NotImplementedException();
}
public override string[] FindUsersInRole(string roleName, string usernameToMatch)
{
throw new NotImplementedException();
}
public override string[] GetAllRoles()
{
throw new NotImplementedException();
}
/// <summary>
/// 重写GetRolesForUser方法获取当前登录用户的所有角色(role)
/// </summary>
/// <param name="username">用户名</param>
/// <returns></returns>
public override string[] GetRolesForUser(string username)
{
using (var context = new dbEntities())
{
//query all roles with current user
var res = (from user in context.users
join role in context.roles on user.Id equals role.UserId
where user.username == username
select role.Role).ToArray();
return res;
}
}
public override string[] GetUsersInRole(string roleName)
{
throw new NotImplementedException();
}
public override bool IsUserInRole(string username, string roleName)
{
throw new NotImplementedException();
}
public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
{
throw new NotImplementedException();
}
public override bool RoleExists(string roleName)
{
throw new NotImplementedException();
}
}
}
在重写的GetRolesForUser()方法中,重写了逻辑,获取当前登录用户的角色(角色管理的前提:用户必须先经过认证处理)。
注意:
通过以上方式的实现,那么role management system会自动调用自定义的provider以及其中的方法
3.在Home控制器中的动作方法,添加角色管理:
上一篇已经讲过了,mvc中的注解属性类:AuthorizeAttribute,用来进行授权处理的,此类中两个比较重要的属性:Roles和User,用来限制于只有具有指定的角色和用户才能访问已授权的动作方法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using AuthenticationDemo.Models;
namespace AuthenticationDemo.Controllers
{
[Authorize] //强制要进行身份验证(拒绝进行匿名访问)
public class HomeController : Controller
{
dbEntities db = new dbEntities();
// GET: Home
[AllowAnonymous] //允许进行匿名访问
public ActionResult Index()
{
return View();
}
[Authorize(Roles ="Admin,Customer")]
public ActionResult getUserList()
{
var user = db.users.ToList();
return View(user);
}
[Authorize(Roles = "Admin")]
public ActionResult About()
{
return View();
}
[Authorize]
public ActionResult Service()
{
return View();
}
}
}
分析:
当已登录的用户通过URL访问有role限制的页面,角色管理系统会自动调用你自定义的provider里的GetRolesForUser(),根据登录用户的username获取当前用户的角色(Role),和Roles属性中的值进行比较,如果有对应的role,允许访问此动作方法,否则不允许访问。
添加getUserList视图:
只有Admin的用户,才能获取所有用户信息
@model IEnumerable<AuthenticationDemo.Models.user>
@{
ViewBag.Title = "getUserList";
}
<h2>getUserList</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.username)
</th>
<th>
@Html.DisplayNameFor(model => model.password)
</th>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.username)
</td>
<td>
@Html.DisplayFor(modelItem => item.password)
</td>
<td>
@*检测当前登录用户是否具有Admin角色*@
@if (User.IsInRole("Admin"))
{
@Html.ActionLink("Edit", "Edit", new { id=item.Id })
@Html.ActionLink("Details", "Details", new { id=item.Id })
@Html.ActionLink("Delete", "Delete", new { id=item.Id })
}
</td>
</tr>
}
</table>
修改_layout 分部视图(主页面的导航部分):
对根据role进行显示/隐藏指定的内容
//检查当前登录用户的Role(根据用户的role 显示 / 隐藏内容
@if (User.Identity.IsAuthenticated)//检查用户是否已登录(登录成功实际上就已经验证了用户)
{
<li><a href="">Dear @User.Identity.Name</a></li>
<li>@Html.ActionLink("Logout", "Logout", "Account")</li>
//检查当前登录用户的Role(根据用户的role 显示 / 隐藏内容
if (User.IsInRole("Admin") || User.IsInRole("Customer")
{
<li> @Html.ActionLink("About us ", "About", "Home")</li>
<li>@Html.ActionLink("User List", "getUserList", "Home")</li>
}
}
else
{
<li>@Html.ActionLink("Login", "Login", "Account")</li>
}
测试案例:
admin用户具有两个role:Admin和Customer
运行程序,发现:
未登录状态下,导航部分,并没有About Us和User List链接,说明我们设置的role已起作用了。
以admin账号进行登录:
链接也已显示出来了
点击User List链接:
用户列表也是ok的
这边是在前台去check用户的角色,然后显示/隐藏指定的页面内容,如果用户是直接使用url去访问,那么就是在动作方法上添加的Role属性去check匹配了,根据是否具有指定role决定是否允许访问。
总结:
角色管理的前提,就是身份的认证,用户处于登录状态才能进行角色管理控制,比如给用户添加或者移除指定的Role等等操作。
具体查询微软文档说明中的这一部分:Role Management,User Identity,and Membership