答应了客户写一个控制数据列的访问控制程序,虽然已经到了深夜1点多了,还是硬着头皮把程序都调整好,文档都写好,明天客户上班了,就可以看到例子程序了,希望能满足客户的实际需要。
其实权限的存储,看透了,也是很简单的事情,就是 “什么对象对什么资源有什么权限?”把这个逻辑关系能保存好就ok了,你这样设计了,别人也容易阅读你的程序,容易理解你的数据库设计,将来也容易维护一些。
用一个思想,前后不矛盾的,把整个系统实现出来,也有些不容易,很多环节会出现前后矛盾,思路混乱的情况,所以时刻要提醒自己,自己的权限系统是按“什么对象对什么资源有什么权限?”的指导思想设计的,若有违背了这个思想,那就仔细深入思考,再重新整理思路。
什么对象:在系统里确定各种对象的唯一性,需要2个参数,一个是对象的类别,一个是对象的主键,就像是ERP里的入库单(单号)。
什么资源:什么资源,也是一样的,也需要一个分类,一个主键来识别资源的唯一性。
什么权限:最简单的做法,就是有一个权限表,只用主键来识别唯一性,而不是用“哪个模块+哪个功能”来识别权限,那样做过于繁琐了,将来的扩展性、可维护性都会很差一些,不能灵活适应各种复杂的情况。
那表格列的控制,也是一样的道理,应该有一个权限定义,这个权限叫“表格列访问控制”,什么对象是指用户还是角色,对什么资源是指各个表的列。
那有一个问题需要解决:这么多表,都有哪些字段?若都靠人工输入,那真的是搞死人,不准确不说,需要反复输入,反复维护,除非有超级耐心,否则难做到准确性、高效性;解决问题的思路是:“我们不是设计了详细的PowerDesigner数据模型吗?不仅仅拿这个生成代码,还可以生成数据表字段的说明文档”
1:首先需要定义一个权限,这个权限叫“表格列访问控制”。
2:我们在PowerDesigner里辛苦设计了表的结构,各个字段的注释等,那先有设计后有实现的原理,数据库里都有什么表、什么字段,应该能从这个设计里自动生成,而不是要人工再输入数据。
3:那我们重复利用这个良好的设计,改进一下代码生成,让代码生成器自动生成这些表的,字段说明。
4:那我们运行一下这些能自动经产生好表结构说明的程序,那我们就可以得到设置里的内容了。

/// 自动生成设置表字段
/// </summary>
private void SetTableColumns()
{
this .UserCenterDbHelper.Open();
BaseRoleManager roleManager = new BaseRoleManager( this .UserCenterDbHelper, this .UserInfo);
roleManager.SetTableColumns();
BaseUserManager userManager = new BaseUserManager( this .UserCenterDbHelper, this .UserInfo);
userManager.SetTableColumns();
BaseStaffManager staffManager = new BaseStaffManager( this .UserCenterDbHelper, this .UserInfo);
staffManager.SetTableColumns();
BaseModuleManager moduleManager = new BaseModuleManager( this .UserCenterDbHelper, this .UserInfo);
moduleManager.SetTableColumns();
this .UserCenterDbHelper.Close();
}
5:那运行好后,数据库里,就会有表结构的字段说明数据(这些都是代码自动生成的,靠人工输入会搞死人的,表结构有变化了,重新运行一次就OK了,省事了,彻底可以做到全自动化了,爽啊)。
6:在运行权限设置页面,用户、角色的字段访问权限可以进行设置了。
7:设置用户的字段访问权限效果图如下:
8:在没控制表格列的访问控制时,运行效果如下:
9:按权限控制后,显示出来的表格为,没有允许访问的字段,不是公开的字段,就无法看到了,都被隐藏掉了:
10:数据列的权限控制代码如下参考:

// All Rights Reserved , Copyright (C) 2010 , Jirisoft , Ltd.
// ------------------------------------------------------------
using System;
using System.Data;
using System.Web.UI.WebControls;
namespace DotNet.Web.Permission
{
using DotNet.Business;
using DotNet.Manager;
using DotNet.Utilities;
/// <remarks>
/// TableColumns
/// 表字段权限的例子
///
/// 修改纪录
///
/// 版本:1.0 2010.07.13 JiRiGaLa 写好例子程序方便别人学习。
///
/// 版本:1.0
///
/// <author>
/// <name> JiRiGaLa </name>
/// <date> 2010.07.13 </date>
/// </author>
/// </remarks>
public partial class TableColumns : BasePage
{
protected void Page_Load( object sender, EventArgs e)
{
// 当然是用户需要登录,否则哪里能知道,现在是判断谁的权限啊?
this .UserInfo = Utilities.Login( " Jirigala_Bao@Hotmail.com " , String.Empty);
// 设置表字段
// this.SetTableColumns();
// 先设置表格的字段状态
this .CheckUserTableColumnsPermission();
// 显示用户
this .GeUserList();
}
/// <summary>
/// 自动生成设置表字段
/// </summary>
private void SetTableColumns()
{
this .UserCenterDbHelper.Open();
BaseRoleManager roleManager = new BaseRoleManager( this .UserCenterDbHelper, this .UserInfo);
roleManager.SetTableColumns();
BaseUserManager userManager = new BaseUserManager( this .UserCenterDbHelper, this .UserInfo);
userManager.SetTableColumns();
BaseStaffManager staffManager = new BaseStaffManager( this .UserCenterDbHelper, this .UserInfo);
staffManager.SetTableColumns();
BaseModuleManager moduleManager = new BaseModuleManager( this .UserCenterDbHelper, this .UserInfo);
moduleManager.SetTableColumns();
this .UserCenterDbHelper.Close();
}
private void GeUserList()
{
// 获取用户列表
BaseUserManager userManager = new BaseUserManager();
DataTable dataTable = userManager.GetDT();
this .grvUser.DataSource = dataTable;
this .grvUser.DataBind();
}
private void CheckUserTableColumnsPermission()
{
// 当前用户能访问那些字段?
this .UserCenterDbHelper.Open();
BaseTableColumnsManager tableColumnsManager = new BaseTableColumnsManager( this .UserCenterDbHelper, UserInfo);
DataTable dataTable = tableColumnsManager.GetTableColumns( this .UserInfo.Id, " Base_User " );
this .UserCenterDbHelper.Close();
for ( int i = 0 ; i < this .grvUser.Columns.Count; i ++ )
{
if ( this .grvUser.Columns[i] is BoundField)
{
BoundField boundField = (BoundField) this .grvUser.Columns[i];
// 这个字段是否可以查看?
boundField.Visible = BaseBusinessLogic.Exists(dataTable, BaseTableColumnsTable.FieldColumnCode, boundField.DataField);
}
}
}
}
}
posted on 2010-07-14 01:08 吉日嘎拉 不仅权通用权限 阅读(1461) 评论(12) 编辑 收藏
评论
1871037#2楼 回复 引用 查看
楼主辛苦,早点睡吧……#3楼 回复 引用 查看
别在首页推销你的权限了!把你的权限怎么实现的写出来,我们顶顶!
#4楼 回复 引用 查看
有一处,请楼主解释:1、为何“是公开”、“允许编辑”、“删除标记”、“允许删除”使用int,而不使用smallint,是否出于与其他数据库兼容性考虑?
2、“创建日期”和“修改日期”为何是“date”,而不是“datetime”?
3、“表名”nvarchar2(50)是否够用?我在使用中表名有长度为120的nvarchar
#5楼 回复 引用 查看
说实话,这样是可以起到一定的作用,但系统设计不能向着这个方向发展,试想想,一个系统有多少表、多少视图、多少存储过程、多少函数,都可以是数据源,都有相应字段,你这个基础字段要有多少,你还是针对用户,应算放大到针对角色,也有不少,如何维护。归根到底,其实是你的"什么对象对什么资源有什么权限?"这个思想出了问题。
第一、如何解决什么对象对什么资源没有权限。
第二、如何解决角色泛滥问题。
第三、不用看代码我也清楚你是怎样达到现有权限目的,但如何对函数、存储过程进行同样的控制。如果控制不了,在你的团队中是否只能使用表和视图来进行数据显示。
第四、如何解决权限维护问题。这个太难了。
#6楼 回复 引用 查看
数据库设计和sqlserver的权限设计类似吧?我猜的#7楼 回复 引用
字段都写到代码里,太搞了,要是哪天数据库结构变了,就杯具了。#8楼 回复 引用 查看
自问自答?
#9楼[楼主] 回复 引用 查看
用好了,就可以删除掉了,又不是不允许删除的,删除掉,总是很容易的吧。#10楼[楼主] 回复 引用 查看
这个你说了不算,哈哈,不好意思啊,你要是我老板就好了,你说了就算了。#11楼[楼主] 回复 引用 查看
1:使用INT,主要是为了数据库的兼容性,Oralce里好像没有smallint的说法。2:这个数据库模型是Oracle数据库的,所以只有date,我自己建立表时,用了sqlserver, 而且是用了smalldatetime,这样效率高一些。
3:“表名”nvarchar2(50),的确不够,听您的建议,修改为120位长的,谢谢您的好建议,衷心感谢,能找出我的缺点,告诉我如何做更好就是我师傅。
#12楼[楼主] 回复 引用 查看
这个要看实际上的需求有多严格,多精确了,一般一个系统里,只有少数几个字段的访问控制会限制,大部分都是公开的,也没必要非这么做,但是当需要对表字段进行限制时,有这么一个不费力的工具可以用上,省事省心。长这么大从来没见过,系统里的每个表,每个字段都需要限制访问权限的,只是类似的订单的进货价、进货商、销售价等等进行限制什么的,相对来说,这些访问控制,都是少数几个表上设置的。
有一个这样的工具维护控制方便呢?还是没工具维护方便呢?还有很多人可能没这方面的思路,毕竟可以起个借鉴的作用吧。
软件想有神奇的细腻的权限,就需要有这么多复杂的相应的控制设置的地方,例如SAP就有几百上千的功能菜单,也不是进销存3个菜单就可以搞定的。
角色泛滥问题,等不是我工具的问题,例如VS2008也防止不了菜鸟乱写程序,我提供的只是工具,同样一把剑,耍的人不通,效果也不通。
至于权限的维护问题:有个通用的工具可以维护N多软件的权限,还是省了不少麻烦,N多人可以学一套权限管理的使用方法就可以了,N个开发人员可以用1种通用的思想来解决实际工作中的问题就可以了,这的确是很不错的事情,何乐而不为呢。
如何对函数、存储过程进行同样的控制:这个权限系统是用SOA的思想编写的,的确对存储过程的控制相对若一些,权限提供的是一个服务,毕竟存储过程调用服务还不是很方便,可能要转换思路,按传入参数的方式进行权限控制了,或者提供一些SQL过滤语句、函数等。
函数,也可以有现成的权限过滤函数可以调用,至于函数你怎么写,是通过制度、管理、测试来控制的,你写好了权限过滤的函数,权限判断的函数,项目里的其他成员,死活不用,那也没办法,人是最难管的,能说服别人按某个思路来写程序都很难的,这些只能是慢慢来了,或者遇到高效的团队,执行力强的,也能贯穿落实得很到位的。
这几年的帖子里,你这个算是很强的一个,给我的印象很深,也能让我感觉出来,你很有深度、高度,不是普通程序员能达到这个高度的,应该是比我境界还高一些。谢谢你的留言,谢谢你的交流,不足之处我会不断改进。