rottenapple

博客园 首页 新随笔 联系 订阅 管理
   最近一段时间,公司要我和另一个同事负责设计一个共同框架为一个内部项目做准备。而这个框架以后也会逐步的应用在公司的其他.net项目中。
所以感觉任务很重,压力很大。虽然上面也清楚我们的能力(很一般的说),所以对框架也只是提出了基本的要求。例如,实现用户权限管理。在这里,我将把我的设计和大家说一下,请大家多多指正。

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);

                    }
                }


   
 
posted on 2008-01-04 17:17  rottenapple  阅读(6620)  评论(15编辑  收藏  举报