仿SiteMap实现Asp.net 网站的菜单和权限管理

在Asp.net中,SiteMap用于站点导航,可以与Menu等控件一起使用实现网站的菜单和权限管理。但是SiteMap提供的方法都是只读的,无法再运行时修改(菜单)导航文件,需要手动修改配置web.sitemap文件,某些情况下,这样做很不方便。

本文即针对这个问题,模仿SiteMap,实现一个可写的菜单和权限控制组件,称之为 MenuMap。

MenuMap高仿SiteMap,使用方法类似,下面进入主题。

1. 模仿Web.sitemap定义配置文件,文件名和位置自定义,比如叫menu.xml。注意在部署是保证network services 账号对该文件有读和写的权限。

格式如下:

<?xml version="1.0" encoding="utf-8"?>
<menuMap>
  <menuMapNode url="" title="管理系统" description="" icon="" roles="">
    <menuMapNode url="" title="业务管理" description="" icon="" roles="">
      <menuMapNode url="Business/b1.aspx" title="待办事宜" description="" icon="" roles="超级管理员,总部经理,地区经理" />
      <menuMapNode url="Business/b2.aspx" title="积分管理" description="" icon="" roles="超级管理员,总部经理,地区经理" />
      <menuMapNode url="Business/b4.aspx" title="工作流" description="" icon="" roles="超级管理员,总部经理" />
      <menuMapNode url="Business/b5.aspx" title="统计报表" description="" icon="" roles="超级管理员,总部经理" />
    </menuMapNode>
    <menuMapNode url="" title="系统管理" description="" icon="" roles="系统管理员,超级管理员">
      <menuMapNode url="SysAdmin/UserMgr.aspx" title="用户管理" description="" icon="" roles="超级管理员,系统管理员" />
      <menuMapNode url="SysAdmin/RolesAndMenu.aspx" title="权限设置" description="" icon="" roles="超级管理员" />
      <menuMapNode url="SysAdmin/AreaMgr.aspx" title="区域信息" description="" icon="" roles="超级管理员" />
      <menuMapNode url="SysAdmin/ClearCache.aspx" title="清理缓存" description="" icon="" roles="超级管理员" />
    </menuMapNode>
  </menuMapNode>
</menuMap>

基本上同sitemap文件,这里menuMapNode, 多一个属性"icon", 用于给菜单添加图标

2. 实现MenuMapNode类,直接上代码:

  1 using System.Collections.Generic;
  2 using System.Linq;
  3 using System.Text;
  4 
  5 namespace NorthRiver
  6 {
  7     public class MenuMapNode
  8     {
  9         public string Title { get; set; }
 10         public string Url { get; set; }
 11         public string Description { get; set; }
 12         public string Roles { get; set; }
 13         public string IconUrl { get; set; }
 14         public MenuMapNode Parent { get; set; }
 15         public IList<MenuMapNode> ChildNodes { get; set; }
 16 
 17         public bool HasChildren
 18         {
 19             get
 20             {
 21                 if (ChildNodes != null && ChildNodes.Count > 0)
 22                     return true;
 23 
 24                 return false;
 25             }
 26         }
 27 
 28         public override string ToString()
 29         {
 30             return string.Format("<menuMapNode url="{0}" title="{1}" description="{2}" icon="{3}" roles="{4}" />", Url, Title, Description,IconUrl, Roles);
 31         }
 32 
 33         public void RemoveRole(string roleName)
 34         {
 35             if (string.IsNullOrEmpty(roleName))
 36                 return;
 37 
 38             if (HasChildren)
 39             {
 40                 foreach (MenuMapNode child in ChildNodes)
 41                 {
 42                     child.RemoveRole(roleName);
 43                 }
 44             }
 45             if (!string.IsNullOrEmpty(Roles))
 46             {
 47                 string[] roleArray = Roles.Split(',');
 48                 StringBuilder sb = new StringBuilder();
 49                 for (int i = 0; i < roleArray.Length; i++)
 50                 {
 51                     if (roleArray[i] != roleName)
 52                     {
 53                         if (i > 0 && sb.Length > 0)
 54                             sb.Append(',');
 55                         sb.Append(roleArray[i]);
 56                     }
 57                 }
 58                 Roles = sb.ToString();
 59             }
 60         }
 61 
 62         public bool HasRole(string role)
 63         {
 64             if (string.IsNullOrEmpty(Roles))
 65                 return true;
 66 
 67             string[] roleArray = Roles.Split(',');
 68             return roleArray.Contains(role);
 69         }
 70 
 71         public bool HasRoles(string[] roleArray)
 72         {
 73             if (string.IsNullOrEmpty(Roles))
 74                 return true;
 75 
 76             if (roleArray == null)
 77                 return false;
 78 
 79             foreach (string role in roleArray)
 80             {
 81                 if (HasRole(role))
 82                     return true;
 83             }
 84 
 85             return false;
 86         }
 87         //是否有角色
 88         public bool HasRoles(string roles)
 89         {
 90             if (string.IsNullOrEmpty(roles))
 91                 return false;
 92 
 93             string[] roleArray = roles.Split(',');
 94             return HasRoles(roleArray);
 95         }
 96         //添加节点
 97         public void AddNode(MenuMapNode childNode)
 98         {
 99             if (childNode != null)
100             {
101                 if (this.ChildNodes == null)
102                     this.ChildNodes = new List<MenuMapNode>();
103 
104                 childNode.Parent = this;
105                 this.ChildNodes.Add(childNode);
106             }
107         }
108 
109         public bool TryMatchUrl(string url, ref MenuMapNode matchNode)
110         {
111             if (this.Url == url)
112             {
113                 matchNode = this;
114                 return true;
115             }
116 
117             if (this.HasChildren)
118             {
119                 foreach (MenuMapNode child in ChildNodes)
120                 {
121                     if (child.TryMatchUrl(url, ref matchNode))
122                         return true;
123                 }
124             }
125 
126             return false;
127         }
128     }
129 }
MenuMapNode

3.实现MenuMap类,直接上代码:

using System;
using System.Collections.Generic;
using System.Web;
using System.Configuration;
using System.Xml;
using System.Text;

namespace NorthRiver
{
    public class MenuMap
    {
        private static string _menuFileName = "MenuMapFile";
        private static string _rootCacheKey = "MenuMapCache";

        public static MenuMapNode RootNode
        {
            get
            {
                return LoadMenu();
            }
        }

        public static MenuMapNode LoadMenu()
        {
            object objRoot = GetCache(_rootCacheKey);
            if (objRoot == null)
            {
                string filename = ConfigurationManager.AppSettings[_menuFileName];
                filename = HttpContext.Current.Server.MapPath(filename);


                XmlReaderSettings setting = new XmlReaderSettings();
                setting.IgnoreComments = true;
                using (XmlReader xmlReader = XmlReader.Create(filename, setting))
                {
                    XmlDocument xmlDoc = new XmlDocument();
                    xmlDoc.Load(xmlReader);

                    XmlNode xmlRoot = xmlDoc.DocumentElement.FirstChild;
                    MenuMapNode menuRoot = new MenuMapNode();
                    menuRoot.Title = xmlRoot.Attributes["title"] == null ? "" : xmlRoot.Attributes["title"].Value;
                    menuRoot.Url = xmlRoot.Attributes["url"] == null ? "" : xmlRoot.Attributes["url"].Value;
                    menuRoot.Description = xmlRoot.Attributes["description"] == null ? "" : xmlRoot.Attributes["description"].Value;
                    menuRoot.IconUrl = xmlRoot.Attributes["icon"] == null ? "" : xmlRoot.Attributes["icon"].Value;
                    menuRoot.Roles = xmlRoot.Attributes["roles"] == null ? "" : xmlRoot.Attributes["roles"].Value;

                    menuRoot.ChildNodes = new List<MenuMapNode>();

                    if (xmlRoot.HasChildNodes)
                    {
                        foreach (XmlNode xmlNode in xmlRoot.ChildNodes)
                            CreateMenuNode(xmlNode, menuRoot);
                    }

                    SetCache(_rootCacheKey, menuRoot);
                    return menuRoot;
                }
            }

            return (MenuMapNode)objRoot;
        }

        private static void CreateMenuNode(XmlNode xmlNode, MenuMapNode parentNode)
        {
            MenuMapNode menuNode = new MenuMapNode();
            menuNode.Title = xmlNode.Attributes["title"] == null ? "" : xmlNode.Attributes["title"].Value;
            menuNode.Url = xmlNode.Attributes["url"] == null ? "" : xmlNode.Attributes["url"].Value;
            menuNode.Description = xmlNode.Attributes["description"] == null ? "" : xmlNode.Attributes["description"].Value;
            menuNode.IconUrl = xmlNode.Attributes["icon"] == null ? "" : xmlNode.Attributes["icon"].Value;
            menuNode.Roles = xmlNode.Attributes["roles"] == null ? "" : xmlNode.Attributes["roles"].Value;
            menuNode.Parent = parentNode;
            menuNode.ChildNodes = new List<MenuMapNode>();

            if (xmlNode.HasChildNodes)
            {
                foreach (XmlNode node in xmlNode.ChildNodes)
                    CreateMenuNode(node, menuNode);
            }

            parentNode.ChildNodes.Add(menuNode);
        }

        public static void Save()
        {
            XmlWriterSettings settings = new XmlWriterSettings();
            //要求缩进
            settings.Indent = true;
            //注意如果不设置encoding默认将输出utf-16
            //注意这儿不能直接用Encoding.UTF8如果用Encoding.UTF8将在输出文本的最前面添加4个字节的非xml内容
            settings.Encoding = new UTF8Encoding(false);
            //设置换行符
            settings.NewLineChars = Environment.NewLine;

            string filename = ConfigurationManager.AppSettings[_menuFileName];
            filename = HttpContext.Current.Server.MapPath(filename);

            MenuMapNode rootNode = RootNode;
            lock (rootNode)
            {
                using (XmlWriter xmlWriter = XmlWriter.Create(filename, settings))
                {
                    //写xml文件开始<?xml version="1.0" encoding="utf-8" ?>
                    xmlWriter.WriteStartDocument();
                    //写根节点
                    xmlWriter.WriteStartElement("menuMap");
                    //递归写SiteMapNode
                    WriteMenuMapNode(xmlWriter, rootNode);
                    xmlWriter.WriteEndElement();

                    XmlDocument doc = new XmlDocument();
                    doc.Save(xmlWriter);
                }
            }
        }

        private static void WriteMenuMapNode(XmlWriter xmlWriter, MenuMapNode node)
        {
            xmlWriter.WriteStartElement("menuMapNode");
            xmlWriter.WriteAttributeString("url", node.Url);
            xmlWriter.WriteAttributeString("title", node.Title);
            xmlWriter.WriteAttributeString("description", node.Description);
            xmlWriter.WriteAttributeString("icon", node.IconUrl);
            xmlWriter.WriteAttributeString("roles", node.Roles);

            if (node.HasChildren)
            {
                foreach (MenuMapNode child in node.ChildNodes)
                    WriteMenuMapNode(xmlWriter, child);
            }

            xmlWriter.WriteEndElement();
        }
    
        public static object GetCache(string CacheKey)
        {
            System.Web.Caching.Cache objCache = HttpRuntime.Cache;
            return objCache[CacheKey];

        }

        public static void SetCache(string CacheKey, object objObject)
        {
            System.Web.Caching.Cache objCache = HttpRuntime.Cache;
            objCache.Insert(CacheKey, objObject);
        }

        public static void RemoveCache()
        {
            System.Web.Caching.Cache objCache = HttpRuntime.Cache;
            objCache.Remove(_rootCacheKey);
        }

    }
}
View Code

4.在web.config中配置菜单文件路径,如:

  <appSettings>
    <add key="MenuMapFile" value="~\menu.xml" />    
  </appSettings>

5.使用举例:

        private void CreateMenu()
        {
            IList<MenuMapNode> lv1Nodes = MenuMap.RootNode.ChildNodes;
            foreach (MenuMapNode node in lv1Nodes)
            {
                MenuPanel menuPanel = CreateMenuPanel(node);
                if (CheckPermissions(node))
                    this.LeftPanel.Items.Add(menuPanel);
            }
        }

        private MenuPanel CreateMenuPanel(MenuMapNode node)
        {
            MenuPanel menuPanel = new MenuPanel();
            menuPanel.Title = node.Title;
            menuPanel.Border = false;

            if (node.HasChildren)
            {
                foreach (MenuMapNode child in node.ChildNodes)
                {
                    Ext.Net.MenuItem item = new Ext.Net.MenuItem();
                    item.Text = child.Title;
                    item.Icon = Icon.ApplicationHome;
                    item.Listeners.Click.Handler = string.Format("e.stopEvent(); loadPage('{0}', '{1}','{2}');",
                        child.Url, "id" + child.Url.GetHashCode(), child.Title);
                    // object o = child.Roles;

                    if (CheckPermissions(child))
                        menuPanel.Menu.Items.Add(item);
                }
            }
            return menuPanel;
        }

        private bool CheckPermissions(MenuMapNode node)
        {
            //未做标记的菜单,对所有角色可见
            if (string.IsNullOrEmpty(node.Roles))
                return true;

            if (Session["user_roles"] == null)
                return false;

            return node.HasRoles((string[])Session["user_roles"]);
        }

补充,MenuMap是可写的,示例:

                if (MenuMap.RootNode.HasChildren)
                    MenuMap.RootNode.ChildNodes.Clear();

                foreach (SubmittedNode sNode in e.RootNode.Children)
                {
                    MenuMapNode mNode = CreateMenuMapNode(sNode);
                    MenuMap.RootNode.AddNode(mNode);
                }

                MenuMap.Save();
原文地址:https://www.cnblogs.com/northriver/p/3229681.html