所以感觉任务很重,压力很大。虽然上面也清楚我们的能力(很一般的说),所以对框架也只是提出了基本的要求。例如,实现用户权限管理。在这里,我将把我的设计和大家说一下,请大家多多指正。
1。总体设计
这部分应该包括用户登陆校验,访问页面校验,显示用户菜单,显示sitepath。这一切,应该只基于一个数据源。
2。数据库设计
说明:
1.如果页面可以被匿名访问,则mod["IsAnyonmous"]=1
2.如果该页面需要显示在menu上,则Mod["Ismenu"]=1
3.CanEdit用来表示这个页面是否可以被这个Role读写。不支持Button级别的权限
4.一个用户可以有多个Role
5.多级菜单的关系用ParentID来维护。
6.公司使用域验证,不需要维护用户名和密码。默认就是打开IE的用户。
3。代码实现
1)使用存储过程来返回排序好的菜单,在MasterPage Load并放入Session中。
是Oracle写的,凑合看吧。
PROCEDURE USP_GETMODULES(
P_USERID in nvarchar2,
P_APPID in nvarchar2,
P_GETMODULES_CURSOR out CUR_USERACCESS_GETMODULES
) AS
v_Level number := 0;
BEGIN
Delete AP_TEMP_MOD;
-- Insert Level0 Items
INSERT into AP_TEMP_MOD SELECT DISTINCT a.MODID,v_Level,to_char(a.MODID),a.ISANONYMOUS
FROM AP_MODS a,AP_MODS_ROLES b,AP_APPS_USERS c
WHERE a.APPID =P_APPID
AND c.USERID = P_USERID
AND a.OBSOLETE = 0
AND b.OBSOLETE = 0
AND c.OBSOLETE = 0
AND a.ParentModID IS NULL
AND a.APPID = c.APPID
AND a.MODID = b.MODID
AND b.ROLEID = c.ROLEID ;-- role
-- Insert subItems
WHILE sql%rowcount >0 loop
v_Level:=v_Level+1;
INSERT into AP_TEMP_MOD SELECT DISTINCT a.MODID,v_Level,b.modSort || to_char(a.DISPLAYORDER),a.ISANONYMOUS
FROM AP_MODS a,AP_TEMP_MOD b ,AP_MODS_ROLES c,AP_APPS_USERS d
WHERE a.APPID =P_APPID
AND d.USERID = P_USERID
AND b.MODLEVEL= v_Level-1
AND a.OBSOLETE = 0
AND a.PARENTMODID = b.modID
AND ((a.ISANONYMOUS = 0
AND c.OBSOLETE = 0
AND d.OBSOLETE = 0
AND a.MODID = c.MODID
AND a.APPID = d.APPID
AND c.ROLEID = d.ROLEID
)
OR( a.ISANONYMOUS = 1
))
; -- role
END loop;
-- Return modules list orderly
OPEN P_GETMODULES_CURSOR For
SELECT * FROM(
SELECT MODID,MODNAME,PARENTMODID,RELATIVEURL,DISPLAYORDER,MODLEVEL,ISMENU,0 as ISANONYMOUS,max(CANEDIT) as CANEDIT,MODSORT
FROM (
SELECT AA.*,BB.CANEDIT
FROM(
SELECT a.MODID,a.MODNAME,a.PARENTMODID,a.RELATIVEURL,a.DISPLAYORDER,a.ISMENU,b.MODLEVEL,b.modsort
FROM AP_MODS a, AP_TEMP_MOD b
WHERE b.ISANONYMOUS = 0 AND a.MODID = b.MODID(+)
) AA,AP_MODS_ROLES BB
WHERE AA.MODID = BB.MODID(+) and BB.OBSOLETE = 0
AND EXISTS (SELECT 1 FROM AP_APPS_USERS ap WHERE bb.ROLEID = ap.ROLEID AND ap.USERID=P_USERID AND ap.OBSOLETE = 0)-- role
)
GROUP BY MODID,MODNAME,PARENTMODID,RELATIVEURL,DISPLAYORDER,ISMENU,MODLEVEL,MODSORT
UNION ALL
SELECT a.MODID,a.MODNAME,a.PARENTMODID,a.RELATIVEURL,a.DISPLAYORDER,b.MODLEVEL,a.ISMENU,1 as ISANONYMOUS,1 as CANEDIT,b.modsort
FROM AP_MODS a, AP_TEMP_MOD b
WHERE a.OBSOLETE = 0
AND b.ISANONYMOUS = 1
AND a.MODID = b.MODID)
ORDER BY MODLEVEL,MODSORT;
导入菜单的代码使用递归来实现。
for (int i = 0; i < list.Count; i++)
{
if (list[i].ParentModID == (int)MenuLevel.FirstLevel
&& list[i].IsMenu == 1)
{
Infragistics.WebUI.UltraWebNavigator.Item parentItem = new Item();
parentItem.Text = list[i].ModName;
// target url.
parentItem.TargetUrl = list[i].RelativeURL;
// add parent items to webmenu.
menu.Items.Add(parentItem);
// call add children items method.
AddChildItems(list, parentItem, i);
}
}
private void AddChildItems(IList<Module> list, Infragistics.WebUI.UltraWebNavigator.Item menuItem, int row)
{
for (int i = 0; i < list.Count; i++)
{
// relationship between the parent items and children items.
if (list[i].ParentModID == list[row].ModID
&& list[i].IsMenu == 1)
{
Item childItem = new Item();
childItem.Text = list[i].ModName;
childItem.TargetUrl = list[i].RelativeURL;
// add children items to parent items.
menuItem.Items.Add(childItem);
// using recursion to add childitem.
AddChildItems(list, childItem, i);
}
}
}
2)加入一个自定义的HttpModule来处理每一次的客户请求。
在 context_AcquireRequest()事件里处理逻辑如下:
判断是否是Aspx的请求
判断Session是否为空,如果为空查找数据库返回该用户可以访问的页面List
根据Url从数据库取出该Module。如果是允许匿名访问,则不作处理。否则遍历查找是否在该用户可以访问的list中
如果可以访问,得到CanEdit设定只读还是可更新。(Aspx页面的Button利用后期绑定和Session来实现Enable/Disable)
3)继承 StaticSiteMapProvider,从数据库取出module关系和列表。此处不需要考虑role,取出全部的modules。因为即使stiepath中包含用户无权访问的path,但是由于在请求的时候已经有过判定,如果他没有权限就无法load这个画面,因此不会造成越权访问。
// Create SiteMapNodes
for (int i = 0; i < list.Count; i++)
{
if (list[i].ModLevel == (int)MenuLevel.RootNode)
{
// add root node
if (nodes.ContainsKey(list[i].ModID))
throw new Exception("Load appliaction failed. One appliaction just can have one root node.");
// Create a new node
rootNode = new SiteMapNode(this, list[i].ModID.ToString(), list[i].RelativeURL, list[i].ModName);
// Record the root node in the dictionary
nodes.Add(list[i].ModID, rootNode);
AddNode(rootNode, null);
}
else
{
// add child node
// Create a new node
SiteMapNode childNode = new SiteMapNode(this, list[i].ModID.ToString(), list[i].RelativeURL, list[i].ModName);
// Record the root node in the dictionary
nodes.Add(list[i].ModID, childNode);
// Get the parent node.
SiteMapNode parentnode = nodes[list[i].ParentModID];
// Add the child node to parent node
AddNode(childNode, parentnode);
}
}