http://www.cnblogs.com/freetalent/archive/2008/11/18/1335681.html
引言
電子商務系統對安全問題有較高的要求,傳統的訪問控制方法DAC(Discretionary Access Control,自主訪問控制模型)、MAC(Mandatory Access Control,強制訪問控制模型)難以滿足複雜的企業環境需求。因此,NIST(National Institute of Standards and Technology,美國國家標準化和技術委員會)於90年代初提出了基於角色的訪問控制方法,實現了用戶與訪問權限的邏輯分離,更符合企業的用戶、組織、數據和應用特徵。ASP.NET是微軟爲了抗衡JSP而推出的新一代ASP(Active Server Pages)腳本語言,它借鑑了JSP的優點,同時它又具有自身的一些新特點。
本文將首先介紹ASP.NET的基本情況和RBAC(Role Based Access Control)的基本思想,在此基礎上,給出電子商務系統中實現用戶權限控制的一種具體方法。
ASP.NET概述
1、ASP.NET
ASP.NET是微軟流行的動態WEB編程技術活動服務器網頁(ASP)的最新版本,但它遠不是傳統ASP簡單升級。ASP.NET和ASP的最大區別在於編程思維的轉換,ASP.NET是真正的面向對象(Object-oriented),而不僅僅在於功能的增強。
在ASP.NET中,Web 窗體頁由兩部分組成:視覺元素(HTML、服務器控件和靜態文本)和該頁的編程邏輯。其中每一部分都存儲在一個單獨的文件中。可視元素在一個擴展名爲 .aspx 文件中創建,而代碼位於一個單獨的類文件中,該文件稱作代碼隱藏類文件擴展名爲.aspx.vb 或 .aspx.cs。這樣,.aspx文件中存放所有要顯示的元素,aspx.vb或.aspx.cs文件中存放邏輯。
2、用戶控件(UserControl)
爲了使用戶能夠根據需要方便地定義控件,ASP.NET引入了 Web 窗體用戶控件的概念。實際上,只要將.aspx稍作修改即可轉換爲 Web 用戶控件,擴展名爲 .ascx,.ascx和.aspx文件一樣也有一個存放邏輯的代碼隱藏類文件,擴展名爲.ascx.vb或.ascx.cs,只是它不能作爲獨立 Web 窗體頁來運行,只有當被包含在 .aspx文件中時,用戶控件才能工作。
通過以下兩個步驟在WEB窗體頁中設置用戶控件:
(1)使用@ Register指令在.aspx文件中註冊用戶控件。如要註冊在放在相對路徑“../UserControl/”下的頭文件headinner.ascx的方法爲:
<%@ Register TagPrefix="Acme" TagName="Head" Src="../UserControl/headinner.ascx" %>
(2)在服務器控件的開始標記和結束標記之間(<form runat=server> </form>) 聲明該用戶控件元素。例如要聲明上面所導入的控件的語法爲:
<Acme: Head runat="server"/>
這樣,該控件就成爲頁的一部分,並將在處理該頁時呈現出來。並且,該控件的公共屬性、事件和方法將向 Web 窗體頁公開並且可以通過編程來使用。根據這個原理,就可以將每個頁面初始化時所要執行的操作(如登錄驗證,角色驗證)封裝在用戶控件當中。
RBAC的基本思想
RBAC(角色訪問控制)的基本思想可簡單地用圖1來表示,即把整個訪問控制過程分成兩步:訪問權限與角色相關聯,角色再與用戶關聯,從而實現了用戶與訪問權限的邏輯分離。
由於RBAC實現了用戶與訪問權限的邏輯分離,因此它極大的方便了權限管理。例如,如果一個用戶的職位發生變化,只要將用戶當前的角色去掉,加入代表新職務或新任務的角色即可,角色/權限之間的變化比角色/用戶關係之間的變化相對要慢得多,並且委派用戶到角色不需要很多技術,可以由行政管理人員來執行,而配置權限到角色的工作比較複雜,需要一定的技術,可以由專門的技術人員來承擔,但是不給他們委派用戶的權限,這與現實中情況正好一致。
用戶權限在.NET中的設計與實現
利用.NET中的用戶控件實現權限控制的基本思想是:根據角色訪問控制(RBAC)的基本原理,給用戶分配一個角色,每個角色對應一些權限,然後利用ASP.NET中的用戶控件(UserControl)來判斷該用戶對應的角色是否對訪問頁面有訪問的權力。
下面將從數據庫設計、添加角色和用戶控件的使用等三方面來闡述具體實現過程。
1、數據庫中表的設計
首先,在數據庫中設計功能模塊表、功能表和角色表等三個表。
(1) 功能模塊表
爲了管理好用戶的權限,首先要組織好系統的模塊,爲此設計了一個功能模塊表。見表1。
(2) 功能表
每個功能模塊所具有的子功能稱爲功能,如商品管理模塊goods(屬於功能模塊的範疇)包含商品信息查詢、商品信息更新、商品信息刪除、商品定價信息查詢以及商品定價信息更新五種功能,功能表的設計見表2。
上面提到的例子可以作爲這樣幾條記錄分別插入功能模塊表和功能表。
insert into TModule values(0,///////////////////////////////////////////////////////////////'商品管理模塊///////////////////////////////////////////////////////////////',///////////////////////////////////////////////////////////////'goods///////////////////////////////////////////////////////////////',5);
insert into Tfunction values(0,///////////////////////////////////////////////////////////////'商品信息查詢///////////////////////////////////////////////////////////////',///////////////////////////////////////////////////////////////'selectgoods///////////////////////////////////////////////////////////////',0);
insert into Tfunction values(1,///////////////////////////////////////////////////////////////'商品信息更新///////////////////////////////////////////////////////////////',///////////////////////////////////////////////////////////////'updategoods///////////////////////////////////////////////////////////////',0);
insert into Tfunction values(2,///////////////////////////////////////////////////////////////'商品信息刪除///////////////////////////////////////////////////////////////',///////////////////////////////////////////////////////////////'deletegoods///////////////////////////////////////////////////////////////',0);
insert into Tfunction values(3,///////////////////////////////////////////////////////////////'商品定價信息查詢///////////////////////////////////////////////////////////////',///////////////////////////////////////////////////////////////'selectgoodsprice///////////////////////////////////////////////////////////////',0);
insert into Tfunction values(4,///////////////////////////////////////////////////////////////'商品定價信息更新///////////////////////////////////////////////////////////////',///////////////////////////////////////////////////////////////'updategoodsprice///////////////////////////////////////////////////////////////',0);
(3) 角色表
角色表的設計關鍵在於角色值的定義,它是一個由0和1組成的類似二進制數的字符串。而功能表中的funcNo (功能編號)字段表示該功能在角色表的roleValue (角色值)字段中的位置,如果該位置對應的數值是0,表示該角色無此權限,如果值爲1,則表示該角色擁有此權限。如角色普通會員的角色值爲100100…00(共100位),如上所示,商品信息查詢的功能編號爲0,角色值100100…00的第0位爲1,所以該普通會員角色擁有商品信息查詢的功能;相反,該角色值的第1位爲0,而功能編號爲1 的功能爲商品信息更新,所以該普通會員角色沒有商品信息更新的權限。它們的關係可由圖2來表示。
2、角色的添加
有了上面幾個表,角色頁面的功能模塊以及其對應的功能都可以從功能模塊表和功能表中讀出,如圖3所示。
在將新角色普通會員插入數據庫時,先將角色值的所有位都置爲0,然後利用.NET Framework 類庫中的Replace函數將角色值中的打上勾的功能相應的功能編號位的值改爲1。
例如,新添加一個角色名爲普通會員的角色,它擁有的功能爲商品信息查詢(功能編號0)和商品定價信息查詢(功能編號3)兩項,則角色值應爲1001000……00(100位),即角色值中第0位和第3位的值爲1,其餘爲0。
3、利用用戶控件實現訪問權限
在定義好用戶控件.ascx文件(head.ascx)及.ascx.cs(head.ascx,cs)文件時,接下去只要在.aspx文件中註冊和聲明它就可以了。
(1) 註冊
<%@ Register TagPrefix="Acme" TagName="Head" Src="../UserControl/headinner.ascx" %>
(2) 聲明
經過實踐,在.aspx文件中聲明.ascx文件可分爲幾種情況:
第一種情況:<Acme:Head runat="server" />
第二種情況:<Acme:Head runat="server" flag=0 funcname1=selectgoods funcname2=updategoods />
第三種情況:<Acme: Head runat="server" flag=1 funcname1= selectgoods funcname2=updategoods />
字段flag是用來控制怎樣進行權限檢查的標誌,funcname指功能表中的功能英文名。如果flag爲空,則不執行權限檢查(第一種情況);否則如果flag=="0",則表示同時具有selectgoods(商品信息查詢)和 updategoods(商品信息更新)這兩種權限的角色所對應的用戶纔有權利查看該頁(第二種情況);否則,如果flag=="1",則認爲,具有selectgoods(商品信息查詢)或 updategoods(商品信息更新)這兩種權限中任意一種權限的用戶就有權利查看該頁(第三種情況)。
上面進行權限檢查的過程全部由用戶控件來實現,其全部方法都封裝在.ascx.cs文件中,其中最主要的一個方法是檢查某一角色是否擁有某一確定權限的checkAuth(string roleId,string funcEName)方法。這個方法的思想如圖4所示。
圖4中roleValue(角色值)的第0位(selectgoods的功能編號)值爲1,表示該角色擁有selectgoods(商品信息查詢)的權限。這樣,我們把對權限檢查的所有邏輯都封裝在了用戶控件中,因此,對WEB窗體頁.aspx文件而言,只需在導入.ascx文件時確定用戶在訪問該頁面時所應擁有的權限,而不需對aspx.cs進行任何改動。
由上所述,可以很清楚地看出,只要在用戶控件中對用戶權限進行控制,再把它包括在.aspx文件中(這件事作者本來就是要做的),那麼在編程的時候就不必考慮複雜的權限問題了。
結束語
本文在開發一個電子商務系統的實踐中發現,公司對系統用戶的權限控制非常重視。因此,設計一個簡單方便又行之有效的權限控制機制對於電子商務系統是必不可少的。本文所提出的基於ASP.NET的電子商務系統用戶權限設計和實現方法已經在實際的工作中得到了驗證,修改指定權限組的操作變得非常方便。
用戶權限設計(二)——用戶認證管理設計方案【轉】
用戶認證管理設計方案
1) 具有創建用戶、修改用戶和刪除用戶的功能: Administrator
2) 具有創建角色和刪除角色的功能: Administrator
Static_User字段名 |
詳細解釋 |
類型 |
備註 |
UserID |
路線編號 |
varchar(20) |
PK |
UserName |
用戶名稱 |
varchar(20) |
|
UserPwd |
用戶密碼 |
varchar(20) |
|
LastSignTime |
最後登陸時間 |
datatime |
|
SignState |
用戶登陸狀態標記 |
int |
|
TickeID |
驗證票記錄編號 |
varchar(128) |
|
|
|
|
|
Static_User字段名 |
詳細解釋 |
類型 |
備註 |
RoleID |
角色編號 |
varchar(20) |
PK |
RoleName |
角色名稱 |
varchar(20) |
|
RoleNote |
角色信息描述 |
varchar(20) |
|
|
|
|
|
Static_User字段名 |
詳細解釋 |
類型 |
備註 |
UserRoleID |
用戶角色編號 |
varchar(20) |
PK |
UserID |
用戶編號 |
varchar(20) |
FK |
RoleID |
角色編號 |
varchar(20) |
FK |
UserRoleNote |
用戶角色信息描述 |
varchar(20) |
|
|
|
|
|
Static_User字段名 |
詳細解釋 |
類型 |
備註 |
PermissionID |
編號 |
varchar(20) |
PK |
PermissionName |
權限名稱 |
varchar(20) |
|
PermissionNote |
全息信息描述 |
varchar(20) |
|
|
|
|
|
Static_User字段名 |
詳細解釋 |
類型 |
備註 |
RolePermissionID |
角色權限編號 |
varchar(20) |
PK |
RoleID |
角色編號 |
varchar(20) |
FK |
PermissionID |
權限編號 |
varchar(20) |
FK |
RolePermissionNote |
角色權限信息描述 |
varchar(20) |
|
|
|
|
|
using System.Web.Services;
using System.Web.Services.Protocols;
// AuthHeader class extends from SoapHeader
public class AuthHeader : SoapHeader {
public string Username;
public string Password;
}
public class HeaderService : WebService {
public AuthHeader sHeader;
...
[WebMethod(Description="This method requires a custom soap header set by the caller")]
[SoapHeader("sHeader")]
public string SecureMethod() {
if (sHeader == null)
return "ERROR: Please supply credentials";
else
return "USER: " + sHeader.Username;
}
HeaderService h = new HeaderService();
AuthHeader myHeader = new AuthHeader();
myHeader.Username = "username";
myHeader.Password = "password";
h.AuthHeader = myHeader;
String result = h.SecureMethod();
public class ClientClass {
public static void Main() {
GenericIdentity ident = new GenericIdentity("Bob");
GenericPrincipal prpal = new GenericPrincipal(ident,
Newstring[] {"Level1"});
LogicalCallContextData data =
new LogicalCallContextData(prpal);
//Enter data into the CallContext
CallContext.SetData("test data", data);
Console.WriteLine(data.numOfAccesses);
ChannelServices.RegisterChannel(new TcpChannel());
RemotingConfiguration.RegisterActivatedClientType(
typeof(HelloServiceClass), "tcp://localhost:8082");
HelloServiceClass service = new HelloServiceClass();
if(service == null) {
Console.WriteLine("Could not locate server.");
return;
}
// call remote method
Console.WriteLine();
Console.WriteLine("Calling remote object");
Console.WriteLine(service.HelloMethod("Caveman"));
Console.WriteLine(service.HelloMethod("Spaceman"));
Console.WriteLine(service.HelloMethod("Bob"));
Console.WriteLine("Finished remote object call");
Console.WriteLine();
//Extract the returned data from the call context
LogicalCallContextData returnedData =
(LogicalCallContextData)CallContext.GetData("test data");
Console.WriteLine(data.numOfAccesses);
Console.WriteLine(returnedData.numOfAccesses);
}
}
using System;
using System.Text;
using System.Runtime.Remoting.Messaging;
using System.Security.Principal;
public class HelloServiceClass : MarshalByRefObject {
static int n_instances;
int instanceNum;
public HelloServiceClass() {
n_instances++;
instanceNum = n_instances;
Console.WriteLine(this.GetType().Name + " has been created.
Instance # = {0}", instanceNum);
}
~HelloServiceClass() {
Console.WriteLine("Destroyed instance {0} of
HelloServiceClass.", instanceNum);
}
public String HelloMethod(String name) {
//Extract the call context data
LogicalCallContextData data =
(LogicalCallContextData)CallContext.GetData("test data");
IPrincipal myPrincipal = data.Principal;
//Check the user identity
if(myPrincipal.Identity.Name == "Bob") {
Console.WriteLine("/nHello {0}, you are identified!",
myPrincipal.Identity.Name);
Console.WriteLine(data.numOfAccesses);
}
else {
Console.WriteLine("Go away! You are not identified!");
return String.Empty;
}
// calculate and return result to client
return "Hi there " + name + ".";
}
}
1)class UserInfoMng() 用戶信息管理類,其中包括方法:
l CreateUserInfo(string UserName string UserPwd) 建立用戶信息,調用存儲過程CreateUserInfo(@UserName,@UserPwd)
l ModifyUserInfo(string UserName string UserPwd) 修改用戶信息,調用存儲過程ModifyUserInfo(@UserName,@UserPwd)
l DeleteUserInfo() 刪除用戶信息,調用存儲過程DeleteUserInfo
(@UserID)
2)class UserAuthentication() 用戶認證類,用來實現用戶角色、權限的設置,包括方法:
l CreatePermissionInfo(string PermissionName string Permissi-
-onNote) 建立權限信息,調用存儲過程CreatePermissionInfo
(@PermissionName,@PermissionNote)
l CreateRoleInfo(string RoleName string RoleNote) 建立角色信息,調用存儲過程CreateRoleInfo(@RoleName,@RoleNote)
l DeleteRoleInfo() 刪除角色信息,調用存儲過程DeleteRoleInfo
(@RoleID)
l GrantUserRole(string UserID string RoleID string UserRoleNote) 授予用戶角色,調用存儲過程GrantUserRole(@UserID,@RoleID,
@UserRoleNote)
l DeleteUserRole() 刪除用戶角色,調用存儲過程DeleteUserRole
(@UserRoleID)
l GrantRolePermission(string RoleID string PermissionID string RolePermissionNote) 授予角色權限,調用存儲過程GrantRolePermission(@RoleID,@PermissionID,@RolePermissionNote)
l DeleteRolePermission() 刪除授予的角色權限,調用存儲過程
DeleteRolePermission(@RolePermissionID)
1)權限設置
class PermissionInfoMng() 用戶權限信息管理類,包括方法:
l CreatePermissionInfo() 建立權限信息
2)用戶管理
class UserInfoMng() 用戶信息管理類,包括方法:
l CreateUserInfo() 建立用戶信息
l ModifyUserInfo() 修改用戶信息
l DeleteUserInfo() 刪除用戶信息
3)用戶授權管理
class RoleInfoMng() 角色信息管理類,包括方法:
l CreateRoleInfo() 建立角色信息
l DeleteRoleInfo() 刪除角色信息
class UserRoleMng() 用戶角色管理類,包括方法:
l GrantUserRole() 授予用戶角色
l DeleteUserRole() 刪除用戶角色
class RolePermissionMng() 角色權限管理類,包括方法
l GrantRolePermission() 授予角色權限
l DeleteRolePermission() 刪除角色權限
4)用戶認證管理
class Authentication() 用戶認證類,包括方法:
l Login(string UserName string UserPwd) 用戶登陸認證,用戶認證通過分配給用戶一個TicketID,否則TicketID則爲null
l Logout() 用戶正常退出