权限控制就是分为“用户登录身份验证”、“控制器方法权限控制”、“界面元素权限控制”三种控制方式,可以为Web开发框架本身提供了很好用户访问 控制和权限控制,使得用户界面呈现菜单、Web界面的按钮和内容、Action的提交控制,均能在总体权限功能分配和控制之下。
本篇文章主要细化这三个方面的介绍,重点介绍“控制器方法权限控制”、“界面元素权限控制”这两种权限控制方式。
1、用户登录控制
登录界面如下所示。
其中登录的前台页面代码如下所示,其中可以在登录界面接收验证码(如果必要的话)。
//实现用户登录 function LoginUserInfo() { //获取单击用户登录按钮的事件 $("#btnLogin").click(function () { //首先获取到要传递到控制器的参数,并且狗造成Json。UserName,UserPassword,Code var postData = { UserName: $("#UserName").val(), Password: $("#Password").val(), Code: $("#Code").val() }; //发送异步请求实现登录 ajax $.ajax({ url: '/Login/CheckUser', data: postData, cache: false, async: true, type: 'post', success: function (data) { if (data == "OK") { window.location.href = "/Home/Index"; } else { alert(data); window.location.href = "/Login/Index"; } } }); }); }
用户登录的后台控制器方法如下所示:
/// <summary> /// 对用户登录的操作进行验证 /// </summary> /// <param name="username">用户账号</param> /// <param name="password">用户密码</param> /// <param name="code">验证码</param> /// <returns></returns> public ActionResult CheckUser(string username, string password, string code) { string result = ""; bool codeValidated = true; if (this.TempData["ValidateCode"] != null) { codeValidated = (this.TempData["ValidateCode"].ToString() == code); } if (string.IsNullOrEmpty(username)) { result = "用户名不能为空"; } else if (!codeValidated) { result = "验证码输入有误"; } else { string ip = GetClientIp(); string macAddr = ""; string identity = BLLFactory<WHC.Security.BLL.User>.Instance.VerifyUser(username, password, MyConstants.SystemType, ip, macAddr); if (!string.IsNullOrEmpty(identity)) { UserInfo info = BLLFactory<WHC.Security.BLL.User>.Instance.GetUserByName(username); if (info != null) { result = "OK"; Session["UserInfo"] = info; Session["Identity"] = info.Name.Trim(); #region 取得用户的授权信息,并存储在Session中 List<FunctionInfo> functionList = BLLFactory<Function>.Instance.GetFunctionsByUser(info.ID, MyConstants.SystemType); Dictionary<string, string> functionDict = new Dictionary<string, string>(); foreach (FunctionInfo functionInfo in functionList) { if (!string.IsNullOrEmpty(functionInfo.ControlID) && !functionDict.ContainsKey(functionInfo.ControlID)) { functionDict.Add(functionInfo.ControlID, functionInfo.ControlID); } } Session["Functions"] = functionDict; #endregion } } else { result = "用户名输入错误或者您已经被禁用"; } } return Content(result); }
从上面的代码,我们可以看到,在用户登录成功后,后台把用户信息、用户权限列表信息放到了Session里面,方便进行后面的权限控制。
然后当前端页面获得成功响应并切换到Home的Index视图前,后台会调用Home的控制器,把一些用户信息放到了ViewBag对象里面,并构造用户的相关菜单项目,代码如下所示。
public class HomeController : BaseController { public ActionResult Index() { if (CurrentUser != null) { ViewBag.FullName = CurrentUser.FullName; ViewBag.Name = CurrentUser.Name; StringBuilder sb = new StringBuilder(); List<MenuInfo> menuList = BLLFactory<Menu>.Instance.GetTopMenu(MyConstants.SystemType); int i = 0; foreach (MenuInfo menuInfo in menuList) { sb.Append(GetMenuItemString(menuInfo, i)); i++; } ViewBag.HeaderScript = sb.ToString();//一级菜单代码 } return View(); }
2、控制器方法权限控制
我们知道,对页面的权限控制,可以分为前端控制和后台代码的控制,控制器方法的权限控制属于后台代码的控制。为了方便基类代码的权限控制,我们定义一个权限控制键的类,用来记录通用的增加、修改、删除、查看、列表、导出等传统控制元素,代码如下所示。
/// <summary> /// 定义常用功能的控制ID,方便基类控制器对用户权限的控制 /// </summary> [DataContract] [Serializable] public class AuthorizeKey { #region 常规功能控制ID /// <summary> /// 新增记录的功能控制ID /// </summary> public string InsertKey { get; set; } /// <summary> /// 更新记录的功能控制ID /// </summary> public string UpdateKey { get; set; } /// <summary> /// 删除记录的功能控制ID /// </summary> public string DeleteKey { get; set; } /// <summary> /// 查看列表的功能控制ID /// </summary> public string ListKey { get; set; } /// <summary> /// 查看明细的功能控制ID /// </summary> public string ViewKey { get; set; } /// <summary> /// 导出记录的功能控制ID /// </summary> public string ExportKey { get; set; } #endregion #region 常规权限判断 /// <summary> /// 判断是否具有插入权限 /// </summary> public bool CanInsert { get; set; } /// <summary> /// 判断是否具有更新权限 /// </summary> public bool CanUpdate { get; set; } /// <summary> /// 判断是否具有删除权限 /// </summary> public bool CanDelete { get; set; } /// <summary> /// 判断是否具有列表权限 /// </summary> public bool CanList { get; set; } /// <summary> /// 判断是否具有查看权限 /// </summary> public bool CanView { get; set; } /// <summary> /// 判断是否具有导出权限 /// </summary> public bool CanExport { get; set; } #endregion /// <summary> /// 默认构造函数 /// </summary> public AuthorizeKey() { } /// <summary> /// 常用构造函数 /// </summary> public AuthorizeKey(string insert, string update, string delete, string view = "") { this.InsertKey = insert; this.UpdateKey = update; this.DeleteKey = delete; this.ViewKey = view; } }
有了这个实体类,我们就可以在控制器的基类BaseController里面实现一些控制逻辑了。首先我们在控制器每次执行方法前,都对权限进行一个转换,并把控制键存储到ViewBage里面,方便前端页面的控制,如下代码所示。
/// <summary> /// 重新基类在Action执行之前的事情 /// </summary> /// <param name="filterContext">重写方法的参数</param> protected override void OnActionExecuting(ActionExecutingContext filterContext) { base.OnActionExecuting(filterContext); //得到用户登录的信息 CurrentUser = Session["UserInfo"] as UserInfo; if (CurrentUser == null) { Response.Redirect("/Login/Index");//如果用户为空跳转到登录界面 } //设置授权属性,然后赋值给ViewBag保存 ConvertAuthorizedInfo(); ViewBag.AuthorizeKey = AuthorizeKey; }
其中ConvertAuthorizedInfo()函数是验证登陆用户是否具有相应的权限的。
/// <summary> /// 对AuthorizeKey对象里面的操作权限进行赋值,用于页面判断 /// </summary> protected virtual void ConvertAuthorizedInfo() { //判断用户权限 AuthorizeKey.CanInsert = HasFunction(AuthorizeKey.InsertKey); AuthorizeKey.CanUpdate = HasFunction(AuthorizeKey.UpdateKey); AuthorizeKey.CanDelete = HasFunction(AuthorizeKey.DeleteKey); AuthorizeKey.CanView = HasFunction(AuthorizeKey.ViewKey); AuthorizeKey.CanList = HasFunction(AuthorizeKey.ListKey); AuthorizeKey.CanExport = HasFunction(AuthorizeKey.ExportKey); }
其中BaseController的控制器基类还定义了判断用户是否有某些权限的逻辑,如果没有没有权限,就会抛出自定义异常(MyDenyAccessException),代码如下。
/// <summary> /// 用于检查方法执行前的权限,如果未授权,返回MyDenyAccessException异常 /// </summary> /// <param name="functionId"></param> protected virtual void CheckAuthorized(string functionId) { if(!HasFunction(functionId)) { string errorMessage = "您未被授权使用该功能,请重新登录测试或联系管理员进行处理。"; throw new MyDenyAccessException(errorMessage); } }
有了上面的这些逻辑,我们在业务控制器基类(BusinessController<B, T>)里面,就可以实现对一些基本操作的API的权限控制了。
/// <summary> /// 本控制器基类专门为访问数据业务对象而设的基类 /// </summary> /// <typeparam name="B">业务对象类型</typeparam> /// <typeparam name="T">实体类类型</typeparam> public class BusinessController<B, T> : BaseController where B : class where T : WHC.Framework.ControlUtil.BaseEntity, new() { /// <summary> /// 插入指定对象到数据库中 /// </summary> /// <param name="info">指定的对象</param> /// <returns>执行操作是否成功。</returns> public virtual ActionResult Insert(T info) { //检查用户是否有权限,否则抛出MyDenyAccessException异常 base.CheckAuthorized(AuthorizeKey.InsertKey); bool result = false; if (info != null) { result = baseBLL.Insert(info); } return Content(result); } /// <summary> /// 更新对象属性到数据库中 /// </summary> /// <param name="info">指定的对象</param> /// <param name="id">主键ID的值</param> /// <returns>执行成功返回<c>true</c>,否则为<c>false</c>。</returns> public virtual ActionResult Update(string id, FormCollection formValues) { //检查用户是否有权限,否则抛出MyDenyAccessException异常 base.CheckAuthorized(AuthorizeKey.UpdateKey); T obj = baseBLL.FindByID(id); if (obj != null) { //遍历提交过来的数据(可能是实体类的部分属性更新) foreach (string key in formValues.Keys) { string value = formValues[key]; System.Reflection.PropertyInfo propertyInfo = obj.GetType().GetProperty(key); if (propertyInfo != null) { try { // obj对象有key的属性,把对应的属性值赋值给它(从字符串转换为合适的类型) //如果转换失败,会抛出InvalidCastException异常 propertyInfo.SetValue(obj, Convert.ChangeType(value, propertyInfo.PropertyType), null); } catch { } } } } bool result = baseBLL.Update(obj, id); return Content(result); }
3、界面元素权限控制
我们从上面那个Web开发框架的主界面图可 以看到,里面对于某个特定的业务,增加、修改、、查看、删除等操作都放在了EasyUI的DataGrid工具栏里面了,为了动态控制用户能访问的界面按 钮,我们需要结合用户权限集合进行界面呈现,首先我们把ToolBar放到一个层里面进行定义,如下代码所示。
//实现对DataGird控件的绑定操作 function InitGrid(queryData) { $('#grid').datagrid({ //定位到Table标签,Table标签的ID是grid url: '/Information/FindWithPager', //指向后台的Action来获取当前用户的信息的Json格式的数据 title: '通知公告', iconCls: 'icon-view', height: 650, width: function () { return document.body.clientWidth * 0.9 },//自动宽度 nowrap: true, autoRowHeight: true, striped: true, collapsible: true, pagination: true, pageSize: 50, pageList: [50, 100, 200], rownumbers: true, //sortName: 'ID', //根据某个字段给easyUI排序 sortOrder: 'asc', remoteSort: false, idField: 'ID', queryParams: queryData, //异步查询的参数 columns: [[ { field: 'ck', checkbox: true }, //选择 { title: '标题', field: 'Title', width: 350, sortable: true }, { title: '编辑者', field: 'Editor', width: 80, sortable: true }, { title: '编辑时间', field: 'EditTime', width: 150, sortable: true }, { title: '附件', field: 'Attachment_GUID', width: 250, sortable: true } ]], toolbar: "#gridtoolbar",
然后在HTML里面添加gridtoolbar的层定义,作为easyUI的表格控件的工具条。由于使用了HTML辅助类来实现界面控件代码控制生 成,因此已经可以达到了界面权限的控制了。使用这种HTML层定义的工具条定义方式,比通过脚本定义的工具条效果少了一个分隔线,其他的都还是一致的。
<div id="gridtoolbar" style="padding: 5px; height: auto"> <div style="margin-bottom: 5px"> @if (@ViewBag.AuthorizeKey.CanInsert) { @Html.ActionLink("添加", null, null, new {onclick="ShowAddDialog()", data_options="iconCls:'icon-add', plain:true", @class = "easyui-linkbutton", href="javascript:void(0)"}) } @if (@ViewBag.AuthorizeKey.CanUpdate) { @Html.ActionLink("修改", null, null, new {onclick="ShowEditOrViewDialog()", data_options="iconCls:'icon-edit', plain:true", @class = "easyui-linkbutton", href="javascript:void(0)"}) } @if (@ViewBag.AuthorizeKey.CanDelete) { @Html.ActionLink("删除", null, null, new {onclick="Delete()", data_options="iconCls:'icon-remove', plain:true", @class = "easyui-linkbutton", href="javascript:void(0)"}) } @if (@Html.HasFunction("Information/View")) { @Html.ActionLink("查看", null, null, new {onclick="ShowEditOrViewDialog('view')", data_options="iconCls:'icon-table', plain:true", @class = "easyui-linkbutton", href="javascript:void(0)"}) } @Html.ActionLink("刷新", null, null, new {onclick="$('#grid').datagrid('reload');", data_options="iconCls:'icon-reload', plain:true", @class = "easyui-linkbutton", href="javascript:void(0)"}) </div> </div>
上面使用了两种方式来判断用户的权限的,一种是使用这种ViewBag对象的树形进行判断,如下所示。
@if (@ViewBag.AuthorizeKey.CanDelete)
还有一种是使用HTML辅助类的扩展方法进行判断,这种方法适用于一些非常规的权限控制集合的判断,如下所示
@if (@Html.HasFunction("Information/View"))
其中HTML辅助类方法是通过扩展静态方法进行实现,代码如下所示。
public static class HtmlHelpers { public static bool HasFunction(this HtmlHelper helper, string functionId) { return Permission.HasFunction(functionId); } public static bool IsAdmin() { return Permission.IsAdmin(); } }
上面的界面控制方法,是通过控制界面代码的生成与否进行权限控制的,前面我们讲了,通过后台代码的控制器方法也是可以实现控制,而且是抛出自定义的错误,那么我们在使用Ajax方法调用的时候,也可以对这个错误信息进行友好显示,提示用户权限不足,前端页面操作代码如下。
//绑定添加按钮的事件 function BindAddEvent() { $("#btnAddOK").click(function () { //判断表单的信息是否通过验证 var validate = $("#ffAdd").form('validate'); if (validate == false) { return false; } var postData = $("#ffAdd").serializeArray(); $.post("/Information/Insert", postData, function (data) { if (data = "true") { //添加成功 1.关闭弹出层,2.刷新DataGird $.messager.alert("提示", "添加成功"); $("#DivAdd").dialog("close"); $("#grid").datagrid("reload"); $("#ffAdd").form("clear"); //本页面的类型为【通知公告】,固定不变 $("#Category").val("通知公告"); } else { $.messager.alert("提示", "添加失败,请您检查"); } }).error(function () { $.messager.alert("提示", "您未被授权使用该功能,请联系管理员进行处理。", 'warning'); }); }); }
以上就是我对Web开发框架中的权限控制几个方面的思路和代码,希望抛砖引玉,获得大家更好的反馈和支持。
相关推荐
在IT行业中,权限控制是后台管理系统中的核心组成部分,它确保用户只能访问他们被授权的资源。本项目结合了layui前端框架和thinkphp后端框架,实现了最细粒度的权限控制,通过读取代码注释的方式来决定用户权限,这...
在IT行业中,权限控制是确保系统安全性和数据保护的关键机制,尤其在Web应用程序中,JavaScript作为客户端脚本语言,其在权限控制中的角色至关重要。本文将深入探讨JavaScript如何实现权限控制,以及它在这个过程中...
在IT行业中,权限控制是确保系统安全性和用户体验的关键部分,特别是在企业级应用中。SpringBoot作为Java领域广泛使用的微服务框架,提供了丰富的功能来帮助开发者实现权限管理。本篇文章将详细探讨如何在SpringBoot...
在C# WinForm应用开发中,权限控制是一个关键的安全组件,它确保了只有授权的用户才能访问特定的功能或数据。本教程将详细讲解如何在C# WinForm环境中实现基于角色的权限控制,包括角色、用户和权限的设置。 首先,...
Java权限控制插件是软件开发中的一个重要组成部分,它主要用于管理和限制不同用户或角色对系统资源的访问。在本文中,我们将深入探讨这个基于Java编写的权限控制插件,特别是其核心概念、设计模式以及实现机制。 ...
在ASP.NET Core中,权限控制是一个关键的组件,用于确保只有具备特定权限的用户才能访问特定的资源或执行特定的操作。在本教程中,我们将探讨如何在ASP.NET Core MVC项目中实现这一功能,特别是如何进行权限的分配。...
Spring Security如何使用URL地址进行权限控制 Spring Security是一个功能强大且广泛应用的Java安全框架,它提供了许多功能,包括身份验证、授权、加密等。其中,权限控制是Spring Security的一个重要组件,它允许...
演示了包括:权限控制、超大附件文件上传、EasyUI基本组件使用等等功能,具体请自行看本示例演示功能 SSHE框架环境需求:JAVA环境:JDK7+;数据库环境:oracle10g+/sqlserver2000+/mysql5+;WEB容器环境:jetty6+/...
【权限控制模型】是信息化系统中至关重要的组成部分,它的设计直接影响到系统的安全性、稳定性和易用性。本文将深入探讨几种常见的访问控制技术,包括自主访问控制(DAC)、强制访问控制(MAC)以及基于角色的访问...
在这个“springboot springsecurity动态权限控制”的主题中,我们将深入探讨如何在Spring Boot项目中集成Spring Security,实现动态权限控制,让菜单权限的管理更加灵活和高效。 首先,我们需要理解Spring Security...
这是一款基于Winform权限控制系统源码,基本上实现了权限管理系统的功能,对于新手来说,还是比较有学习价值的,值得推荐一下,感兴趣的朋友可以下载学习一下。 二、功能介绍 1、用户管理 2、组管理 3、用户授权 ...
### 前后端分离下的权限控制设计 随着前端框架如React、Angular和Vue的兴起,前后端分离架构成为主流趋势。然而,这种架构模式带来了新的挑战,尤其是关于权限控制的问题。本文旨在探讨如何在前后端分离的架构下...
在这个“Struts2拦截器实现权限控制demo”中,我们将深入探讨如何利用拦截器来实现细粒度的用户权限管理。 首先,我们需要了解Struts2中的拦截器工作原理。拦截器是基于Java的动态代理模式实现的,它们按照配置的...
### Web业务系统权限控制知识点详解 #### 一、概述 在现代Web应用开发中,权限控制是一项非常重要的功能。良好的权限控制系统能够确保只有授权的用户才能访问特定的资源和服务,从而提高了系统的安全性与稳定性。本...
在ASP中实现权限控制是确保网站安全和数据保护的关键环节。此压缩包文件包含的内容显然与ASP用户权限设置相关,特别是结合了Access数据库进行用户管理。 ASP中的权限控制主要涉及到以下几个方面: 1. **身份验证**...
该发明涉及一种基于Vue.js和Django的权限控制系统,它主要关注的是在互联网应用程序中实现高效且严格的用户权限管理。Vue.js是一种轻量级的前端JavaScript框架,它以其易用性、灵活性和组件化特性而受到开发者的青睐...
"基于Struts2拦截器的权限控制.doc"文档很可能是提供了一个具体的案例,详细讲解了如何创建并使用拦截器进行权限控制。文档可能会涵盖以下内容: 1. 创建自定义拦截器类,实现`Interceptor`接口,重写`intercept()`...
在Java编程语言中,访问权限控制是至关重要的一个部分,它确保了代码的封装性和安全性。本主题将深入探讨Java中的访问修饰符及其在源代码中的应用。 首先,Java提供了四种基本的访问权限控制修饰符: 1. **public*...
### 帆软报表数据权限控制设计文档 #### 一、背景与需求描述 随着企业对数据精细化管理的要求越来越高,特别是在跨境电商行业中,如何确保不同层级的员工能够访问他们需要的数据,同时保护敏感信息不被非授权人员...
项目概述:本源码为基于角色基础访问控制(RBAC)模型的中小型应用开发平台,采用前后端分离架构。...该平台为开发人员提供了一个具有完善权限控制的后台管理系统,支持快速开发具有复杂权限需求的中后台应用。