做權限,表的結構我覺得大家都差不多了吧?模塊表、用戶表、用戶組表、用戶組權限表,這四個表,肯定都是固定了的,一個用戶可以屬於多個用戶組,一個用戶組可以擁有多個權限(就是可以訪問多個模塊)
有時候還會再加一個用戶所屬性用戶組表,這個表也有人會在用戶表裏加一個字段記錄用戶所屬用戶組的全部用戶組編號的組合字符串
模塊表記錄系統裏有幾個模塊,簡單的系統可以把表結構設置得簡單一點,只記錄編號和描述就可以了,複雜的系統可以把表結構設置得複雜一些,像樹形的結構,有上下級的關係
用戶表記錄所有可以登錄的人員
用戶組表實際上就是權限組表,把人員分類,按組賦給權限
用戶組權限表,就是把用戶組和模塊對應起來,記錄下每個用戶組可以訪問的權限是什麼,這個表一般有兩種結構:1、用戶組編號、模塊編號、是否有權;2、用戶組編號、所有有權訪問的模塊的模塊編號的組合字符串
對這些表怎麼管理,這裏不想管了,這個博客(user1/9/archives/2007/3551.html)寫的這種方法就是用在複雜的權限表的管理的,用TreeView顯示有上下級關係的模塊關係
剛剛開始做OA的時候,發過一個帖子(http://www.tiantiansoft.com/bbs/dispbbs.asp?boardid=40&id=149555),我在做OA時,最後使用的方法很複雜,複雜到自己都描述不清楚,我用的是static DataTable,同樣寫了一個類來管理所有權限,每個頁面的權限判斷,主要是通過這個頁面的地址檢索DataTable裏的記錄判斷的
下面開始講利用static的Dictionary做權限的管理,嗯,我可能會說得很亂,就是,如果現在不記下來,明天我記不下這個東西了,現在很想去玩了,就是,一定要記下來,我一點一點說
1、我沒有使用頁面的地址,檢索權限,我直接給頁面賦了一個頁面編號值
不知道你們還記不記得在做ASP的時候,權限,經常是在頁面的一開始時賦給一個頁面編號,再通過這個編號取值的,這樣做有點像用pb寫軟件的時候先給每個window賦值一樣
這種做法的優點是:省了通過地址取模塊編號這一步,還有就是如果系統裏使用了UrlRewritingNet重寫url,也可以不用害怕取不到原本的地址
這種做法的缺點是:增加了開發時的勞動,每添加一個頁面,就要自己把這個頁面的編號寫正確
這種做法要注意的是頁面的執行順序(user1/9/archives/2007/4020.html),如果使用了母版,執行順序是這樣的:ContentPage.PreInit - > Master.Init -> ContentPage.Init
我們要在Master.Init事件裏判斷用戶權限,所以要在ContentPage.PreInit事件裏對頁面賦值
還有,爲了把每個頁面的操作減少到最小,儘量把重複的代碼寫在母版裏,所以把頁面編號這個屬性,也設置在母版裏,這樣,爲了在每個頁面都可以調用到這個屬性,就需要用到MasterType強化Mater類
這個是母版頁中的內容
#region 檢查權限
private string pageCode = "";
public string PageCode
{
set { pageCode = value; }
get { return pageCode; }
}
protected void Page_Init(object sender, EventArgs e)
{
if (Session["gcs"] == null)
{
Response.Write("<p>還沒登錄,請<a href=/"Login.aspx/">登錄</a>");
Response.End();
}
if (AccessControl.GetAccess(Session["gcs"].ToString(), pageCode))
{
Response.Write("<p>有權訪問</p>");
}
else
{
Response.Write("<p>沒有權訪問</p>");
//Response.End();
}
}
在每個頁面的aspx文件中設置
<%@ MasterType VirtualPath="~/MasterPage.master" %>
在每個頁面的.aspx.cs文件中設置
protected void Page_PreInit(object sender, EventArgs e)
{
Master.PageCode = "02";
}
2、編寫權限控制類,因爲這個類裏用到的成員和方法都可以算是全局的,所以我使用了static,構造函數也使用了靜態構造函數
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections.Generic;
/// <summary>
/// AccessControl 的摘要說明
/// </summary>
public class AccessControl
{
#region 三個靜態成員:模塊字典、用戶組字典、用戶組權限字典
static Dictionary<string, string> module = new Dictionary<string, string>();
static Dictionary<int, string> group = new Dictionary<int, string>();
static Dictionary<int, string> access = new Dictionary<int, string>();
public Dictionary<string, string> Module
{
get { return module; }
set { module = value; }
}
public Dictionary<int, string> Group
{
get { return group; }
set { group = value; }
}
public Dictionary<int, string> Access
{
get { return access; }
set { access = value; }
}
#endregion
#region 靜態構造函數
static AccessControl()
{
//HttpContext.Current.Response.Write("<p>初始化數據</p>");
module.Add("01", "首頁");
module.Add("02", "瀏覽");
module.Add("03", "添加");
module.Add("04", "修改");
module.Add("05", "刪除");
group.Add(1, "管理員組");
group.Add(2, "錄入組");
group.Add(3, "閱讀組");
access.Add(1, "|01|02|03|04|05|"); //管理員組權限
access.Add(2, "|01|02|03|"); //錄入組權限
access.Add(3, "|01|02|"); //閱讀組權限
}
#endregion
#region 檢查編號是groupCode的用戶組,有沒有編號是moduleCode的權限
public static bool GetAccess(string groupCodeStr, string moduleCode)
{
string[] groupCodeArray;
groupCodeArray = groupCodeStr.Split('|');
foreach (string groupCode in groupCodeArray)
{
if (groupCode == null || groupCode.Equals(""))
{
continue;
}
try
{
if (GetAccess(Convert.ToInt32(groupCode), moduleCode))
{
return true;
}
}
catch (FormatException)
{ }
}
return false;
}
public static bool GetAccess(int groupCode, string moduleCode)
{
try
{
//HttpContext.Current.Response.Write("<p>groupCode = " + groupCode.ToString() + ",moduleCode = " + moduleCode + ",access[" + groupCode.ToString() + "] = " + access[groupCode]);
moduleCode = "|" + moduleCode + "|";
if (access[groupCode].IndexOf(moduleCode) > -1)
{
return true;
}
}
catch (KeyNotFoundException)
{
//默認沒有設置到模塊字典裏的頁面,是全體可以訪問的頁面
//HttpContext.Current.Response.Write("<p>沒有對應值:groupCode=" + groupCode.ToString() + ",moduleCode=" + moduleCode);
return true;
}
return false;
}
#endregion
}
這裏面我全部都是直接添加的測試內容,如果是正式用在系統裏,可以把靜態構造函數修改一下,從數據庫中讀取對應的數據添加就可以了
解決一下三個成員:
module,模塊字典,key是模塊編號,value是模塊描述
group:用戶組字典,key是用戶組編號,value是用戶組描述
access:用戶組權限字典,key是用戶組編號,value是這個用戶組可以訪問的所有模塊的模塊編號的組合字符串
他們通過三個索引器管理,這三個索引器現在只是用在Login.aspx頁面中測試,如果是正式的系統,靜態構造函數是從數據庫中讀取的數據,這樣,每當我們修改過數據庫中的數據,我們就需要使用索引器重新寫這三個成員的值了
我覺得沒有別的要記錄了,給出我測試的例子:UploadFiles/2007-8/825715849.rar
WebConfig文件中自定義頁面現在設置成Off了,如果有需要,可以改成On