概述
有关系统权限的设计,有诸多的方案&实现方法,甚至不乏有权限相关的通用组件,当然这些可能都局限于特定的业务场景,简单的抑或是复杂的,正如它不可能真正满足所有的需求;本文通过另一个维度来实现系统权限的控制,当然系统方案的采用主要由系统的业务场景决定,整个实现过程相对繁杂,点到为止。
§ 概述
根据业务性的需要,本次设计复合了以下模式:
1、组合
将权限结构组织成树状结构,使整体-部分的使用拥有一致性
2、外观
权限组件通过外观,提供给外部、组件调用,组合内部诸多实现接口
3、远程适配
适配远程接口,转换为内部统一模型,有关远程适配参见:
http://blog.csdn.net/webwalker/article/details/5652270
§ 名词解释
会员角色:最高级别用户的权限角色,简称MR
操作员角色:从属于会员下的权限角色,简称OR
权限组:以下简称为Role
§ 业务场景
摘要如下:
1、 用户群体
会员(1) à 操作员(*)
一个操作员只从属于一个会员,一个会员拥有不固定数量的操作员
2、 用户类型
已注册未激活用户、未认证用户、签约用户、未签约用户、签约过期用户、操作员用户
不同类别的用户,拥有对应的不固定数量的MR、OR权限集
3、 业务产品
分为需签约、不需要签约两类,签约特定的产品则拥有这类产品下属的特定业务权限,不需要签约的通常默认按以上用户不同阶段默认分配;另外既是签约,则有一定的实效性,签约的过程同样也是系统授权的过程。
4、 用户权限分类
分为系统级别权限和用户自定义级别权限:
系统类权限:需要预先定义的固定权限集合,可在签约时授予,也可在建立、注册用户时默认分配
自定义权限:有限的授权范围内,用户自行设定权限集
5、 权限定义
一个权限Item可包含多个页面(URL),一个权限可从属于多个权限角色,
6、 权限的展现形式
一方面通过菜单的形式显示给用户,另一方面通过页面标签的形式
菜单方式可有两种情况:显示所有菜单(有权限、无权限),用户访问后由系统最终验证是否有权限,另一种为只显示当前用户有权限的菜单。
通过菜单的形式已经确定了权限之间存在着层级关系。
<menu>
<menuitem id="MGR_ACCOUNT" name="test" url="test.aspx" target="">
<menuitem id="ACC_HOME" name="test1" url="test1.aspx" target="">
<url label="test" code="C1000001" actionUrl="/test12.aspx" domainPath="" imgUrl="" target="" />
</menuitem>
<menuitem id="ACC_INFO" name="test2" url="/test2.aspx" target="" />
<menuitem id="ACC_DETAIL" name="test3" url="/test3.aspx" target="" />
<menuitem id="ACC_SUMMARY" name="test4" url="/test4.aspx" target="" />
<menuitem id="ACC_REC_DOWN" name="test5" url="/test5.aspx" target="" />
</menuitem>
</menu>
7、 权限验证
(1) 全局验证URL及用户拥有的访问权限
(2) 验证某个URL中对应页面元素的操作、查看等权限
(3) 验证产品实效性及权限
8、图示
§ 分析设计
1、 数据结构
通常需主要建立:
(1) 基础会员表
(2) 基础权限数据表(系统级别)
(3) 用户自定义权限数据表
(4) MR关系表
(5) OR关系表
(6) 签约的产品表
(7) 签约产品和MR角色关系表
2、 权限验证
§ 设计实现
1、权限树结构(结构组合)
权限树内容信息存储:
/// <summary>
/// 权限树内容信息
/// (菜单、权限集成)
/// 结构1
/// |--菜单
/// |--菜单
/// |--菜单
/// |--URL
/// |--页面元素
/// 结构2:menu、URL权限分开
/// </summary>
[Serializable]
public class AuthSchema
{
/// <summary>
/// 权限ID
/// </summary>
public string ID
{
get;
set;
}
/// <summary>
/// 父亲ID
/// </summary>
public string ParentID
{
get;
set;
}
/// <summary>
/// 权限名称
/// </summary>
public string Name
{
get;
set;
}
/// <summary>
/// 权限URL
/// (绝对路径)
/// </summary>
public string Url
{
get;
set;
}
/// <summary>
/// 打开的目标位置
/// </summary>
public string Target
{
get;
set;
}
/// <summary>
/// 索引
/// </summary>
public string Index
{
get;
set;
}
/// <summary>
/// 排序
/// </summary>
public int Sort
{
get;
set;
}
}
2、索引树的建立、查找
建立:
/// <summary>
/// 树形结构相关处理
/// </summary>
internal class TreeService
{
#region Init
static readonly TreeService _Instance = new TreeService();
/// <summary>
/// Instance
/// </summary>
public static TreeService Instance
{
get
{
return _Instance;
}
}
#endregion
#region Tree
/// <summary>
/// 权限Schema
/// </summary>
AuthSchema s = null;
/// <summary>
/// 节点索引计数器
/// </summary>
Dictionary<string, int> nodeDic = new Dictionary<string, int>();
menu[] menuList;
/// <summary>
/// 构造树形结构
/// </summary>
/// <param name="menus"></param>
public void Construct()
{
menuList = MenuService.Instance.MenuList;
//Create tree structure
AuthComposite Tree = new AuthComposite(new AuthSchema
{
ID = "-1",
Name = "Root"
});
//construct from root node
menu[] list = GetNodes("0");
//Fill Tree
BuildTree(list, Tree);
//保存、缓存树结构
MenuService.Instance.SetMenu(Tree);
}
/// <summary>
/// 根据父节点构造树形结构
/// </summary>
/// <param name="menus"></param>
/// <param name="parentNode"></param>
public void BuildTree(menu[] menus, AuthCompontent parentNode)
{
int index = 0;
foreach (menu item in menus)
{
s = new AuthSchema();
s.ID = item.id;
s.Name = item.label;
s.Url = item.actionUrl;
s.Sort = item.sort;
s.Target = item.target;
s.Index = index.ToString();
s.ParentID = parentNode.AuthTree.ID;
AuthComposite node = new AuthComposite(s);
parentNode.Add(node);
#region 添加树索引
AddNodeIndex(item.id);
if (String.IsNullOrEmpty(parentNode.AuthTree.Index)) s.Index = index.ToString();
else s.Index = parentNode.AuthTree.Index + AuthConsts.Spliter + GetNodeIndex(s.ParentID);
#endregion
if (GetNodes(s.ID).Length > 0)
{
BuildTree(GetNodes(s.ID), node);
}
}
}
/// <summary>
/// 根据索引定位 多叉树 结构中的某一元素
/// </summary>
/// <param name="c"></param>
/// <param name="index">索引位置</param>
/// <returns></returns>
public AuthCompontent IndexNode(AuthComposite c, int index)
{
return c.ChildNodes[index];
}
/// <summary>
/// 添加节点索引
/// </summary>
/// <param name="key"></param>
void AddNodeIndex(string key)
{
if (!nodeDic.ContainsKey(key))
nodeDic.Add(key, 0);
else
nodeDic[key] += 1;
}
/// <summary>
/// 获取树节点索引
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
string GetNodeIndex(string key)
{
if (!nodeDic.ContainsKey(key))
{
return string.Empty;
}
string copy = nodeDic[key].ToString();
nodeDic[key] += 1;
return copy;
}
/// <summary>
/// 按升序方式,获取父节点下第一层级菜单信息
/// </summary>
/// <param name="parentId"></param>
/// <returns></returns>
public menu[] GetNodes(string parentId)
{
var node = (from m in menuList
orderby m.sort
where m.parentId == parentId
select m).ToArray();
return node;
}
#endregion
}
查找:
/// <summary>
/// 根据索引路径,查找各层级菜单集合
/// 方便自由组合各菜单界面位置、样式
/// </summary>
/// <param name="indexString">待查找的索引路径</param>
/// <returns></returns>
public List<AuthCompontent> GetSubMenu(string indexString)
{
AuthComposite tree = GetMenu();
string[] index = indexString.Split(',');
foreach (string s in index)
{
tree = TreeService.Instance.IndexNode(tree, Convert.ToInt32(s)) as AuthComposite;
}
return tree.ChildNodes;
}
3、外部调用
4、权限验证
分别在HttpHandler层提供全局控制、单独的页面访问提供授权验证借口、单独的业务点&URL提供授权验证
§ 应用
1、有关菜单呈现,参见:
http://blog.csdn.net/webwalker/article/details/5338873
2、URL访问时,根据访问页面,自动选中对应的一级、二级菜单
<pages>
<page id="" url="/test.aspx" path="//MGR_ACCOUNT/ACC_INFO"></page>
<page id="" url="/test.aspx" path="//MGR_ACCOUNT/ACC_DETAIL"></page>
<page id="" url="/test.aspx" path="//MGR_ACCOUNT/ACC_SUMMARY"></page>
<page id="" url="/test.aspx" path="//MGR_ACCOUNT/ACC_SUMMARY"></page>
<page id="" url="/test.aspx" path="//MGR_ACCOUNT/ACC_REC_DOWN"></page>
</pages>
3、URL访问时,根据访问页面,自动验证当前URL是否需要附加业务逻辑校验
eg: 验证是否需要实名、是否……
<Root Remark="业务、调用权限配置, 限签约产品相关功能组、自定义功能组">
<Method Name="" Desc="xx管理" url="/test.aspx" FunctionID="MGR_OPERATOR" IsNeedSign="1"></Method>
<Method Name="" Desc="xx" url="/test.aspx" FunctionID="MGR_OPERATOR" IsNeedSign="1"></Method>
</Root>
§ 总结
写的比较仓促,设计部分主要侧重于如何进行权限控制,而对权限数据结构层没有具体涉及,可能也没有啰嗦的必要。
最后
以上就是细腻马里奥为你收集整理的《复合模式》复杂系统权限控制&设计的全部内容,希望文章能够帮你解决《复合模式》复杂系统权限控制&设计所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复