1 設(shè)計思路
為了設(shè)計一套具有較強可擴展性的用戶認證管理,需要建立用戶,、角色和權(quán)限等數(shù)據(jù)庫表,,并且建立之間的關(guān)系,具體實現(xiàn)如下,。 1.1 用戶用戶僅僅是純粹的用戶,,用來記錄用戶相關(guān)信息,如用戶名,、密碼等,,權(quán)限是被分離出去了的。用戶(User)要擁有對某種資源的權(quán)限,必須通過角色(Role)去關(guān)聯(lián),。 用戶通常具有以下屬性: ü 編號,,在系統(tǒng)中唯一。 ü 名稱,,在系統(tǒng)中唯一,。 ü 用戶口令。 ü 注釋,,描述用戶或角色的信息,。 1.2 角色角色是使用權(quán)限的基本單位,,擁有一定數(shù)量的權(quán)限,,通過角色賦予用戶權(quán)限,通常具有以下屬性: ü 編號,,在系統(tǒng)中唯一,。 ü 名稱,,在系統(tǒng)中唯一。 ü 注釋,,描述角色信息 1.3 權(quán)限權(quán)限指用戶根據(jù)角色獲得對程序某些功能的操作,,例如對文件的讀、寫,、修改和刪除功能,,通常具有以下屬性: ü 編號,在系統(tǒng)中唯一,。 ü 名稱,,在系統(tǒng)中唯一。 ü 注釋,,描述權(quán)限信息 1.4 用戶與角色的關(guān)系一個用戶(User)可以隸屬于多個角色(Role),,一個角色組也可擁有多個用戶,用戶角色就是用來描述他們之間隸屬關(guān)系的對象,。用戶(User)通過角色(Role)關(guān)聯(lián)所擁有對某種資源的權(quán)限,,例如 l 用戶(User): UserID UserName UserPwd 1 張三 xxxxxx 2 李四 xxxxxx …… l 角色(Role): RoleID RoleName RoleNote 01 系統(tǒng)管理員 監(jiān)控系統(tǒng)維護管理員 02 監(jiān)控人員 在線監(jiān)控人員 03 調(diào)度人員 調(diào)度工作人員 04 一般工作人員 工作人員 …… l 用戶角色(User_Role): UserRoleID UserID RoleID UserRoleNote 1 1 01 用戶“張三”被分配到角色“系統(tǒng)管理員” 2 2 02 用戶“李四”被分配到角色“監(jiān)控人員” 3 2 03 用戶“李四”被分配到角色“調(diào)度人員” …… 從該關(guān)系表可以看出,用戶所擁有的特定資源可以通過用戶角色來關(guān)聯(lián),。 1.5 權(quán)限與角色的關(guān)系一個角色(Role)可以擁有多個權(quán)限(Permission),,同樣一個權(quán)限可分配給多個角色。例如: l 角色(Role): RoleID RoleName RoleNote 01 系統(tǒng)管理員 監(jiān)控系統(tǒng)維護管理員 02 監(jiān)控人員 在線監(jiān)控人員 03 調(diào)度人員 調(diào)度工作人員 04 一般工作人員 工作人員 …… l 權(quán)限(Permission): PermissionID PermissionName PermissionNote 0001 增加監(jiān)控 允許增加監(jiān)控對象 0002 修改監(jiān)控 允許修改監(jiān)控對象 0003 刪除監(jiān)控 允許刪除監(jiān)控對象 0004 察看監(jiān)控信息 允許察看監(jiān)控對象 …… l 角色權(quán)限(Role_Permission): RolePermissionID RoleID PermissionID RolePermissionNote 1 01 0001 角色“系統(tǒng)管理員”具有權(quán)限“增加監(jiān)控” 2 01 0002 角色“系統(tǒng)管理員”具有權(quán)限“修改監(jiān)控” 3 01 0003 角色“系統(tǒng)管理員”具有權(quán)限“刪除監(jiān)控” 4 01 0004 角色“系統(tǒng)管理員”具有權(quán)限“察看監(jiān)控” 5 02 0001 角色“監(jiān)控人員”具有權(quán)限“增加監(jiān)控” 6 02 0004 角色“監(jiān)控人員”具有權(quán)限“察看監(jiān)控” …… 由以上例子中的角色權(quán)限關(guān)系可以看出,,角色權(quán)限可以建立角色和權(quán)限之間的對應(yīng)關(guān)系,。 1.6 建立用戶權(quán)限用戶權(quán)限系統(tǒng)的核心由以下三部分構(gòu)成:創(chuàng)造權(quán)限、分配權(quán)限和使用權(quán)限,。 第一步由Creator創(chuàng)造權(quán)限(Permission),,Creator在設(shè)計和實現(xiàn)系統(tǒng)時會劃分。利用存儲過程CreatePermissionInfo(@PermissionName,@PermissionNote)創(chuàng)建權(quán)限信息,指定系統(tǒng)模塊具有哪些權(quán)限,。 第二步由系統(tǒng)管理員(Administrator)創(chuàng)建用戶和角色,,并且指定用戶角色(User-Role)和角色權(quán)限(Role-Permission)的關(guān)聯(lián)關(guān)系。 1) Administrator具有創(chuàng)建用戶,、修改用戶和刪除用戶的功能:
l 存儲過程CreateUserInfo(@UserName,@UserPwd)創(chuàng)建用戶信息,; l 存儲過程ModifyUserInfo(@UserName,@UserPwd)修改用戶信息; l 存儲過程DeleteUserInfo(@UserID)刪除用戶信息,; 2) Administrator具有創(chuàng)建角色和刪除角色的功能:
l 存儲過程CreateRoleInfo(@RoleName,@RoleNote)創(chuàng)建角色信息,; l 存儲過程DeleteRoleInfo(@RoleID)刪除角色信息; 3)Administrator具有建立用戶和角色,、角色和權(quán)限的關(guān)聯(lián)關(guān)系功能: l 存儲過程GrantUserRole(@UserID,@RoleID,@UserRoleNote)建立用戶和角色的關(guān)聯(lián)關(guān)系,; l 存儲過程DeleteUserRole(@UserRoleID)刪除用戶和角色的關(guān)聯(lián)關(guān)系; l 存儲過程GrantRolePermission(@RoleID,@PermissionID,@RolePermissionNote)建立角色和權(quán)限的關(guān)聯(lián)關(guān)系,; l 存儲過程DeleteRolePermission(@RolePermissionID)刪除角色和權(quán)限的關(guān)聯(lián)關(guān)系,; 第三步用戶(User)使用Administrator分配給的權(quán)限去使用各個系統(tǒng)模塊。利用存儲過程GetUserRole(@UserID, @UserRoleID output),GetRolePermission(@RoleID,@Role- -PermissinID output)獲得用戶對模塊的使用權(quán)限,。 1.7 用戶認證實現(xiàn)當(dāng)用戶通過驗證后,,由系統(tǒng)自動生成一個128位的TicketID保存到用戶數(shù)據(jù)庫表中,建立存儲過程Login(@UserID,@UserPwd,@TicketID output)進行用戶認證,,認證通過得到一個TicketID,,否則TicketID為null。其流程圖如下: 圖1 Login流程圖 得到TicketID后,,客戶端在調(diào)用服務(wù)端方法時傳遞TicketID,,通過存儲過程JudgeTicketPermission(@TicketID,@PermissionID)判斷TicketID對應(yīng)的用戶所具有的權(quán)限,并根據(jù)其權(quán)限進行方法調(diào)用,。 當(dāng)用戶退出系統(tǒng)時,,建立存儲過程Logout(@UserID)來退出系統(tǒng)。當(dāng)用戶異常退出系統(tǒng)時,,根據(jù)最后的登陸時間(LastSignTime)確定用戶的TickeID,,建立存儲過程ExceptionLogout(@UserID,@LastSignTime)處理用戶的異常退出,。 圖2 Logout流程圖 WebService可以采用SoapHeader中寫入TicketID來使得TicketID從客戶端傳遞給服務(wù)端,。.Net Remoting可以采用CallContext類來實現(xiàn)TicketID從客戶端傳遞給服務(wù)端。 2 數(shù)據(jù)庫設(shè)計
2.1 數(shù)據(jù)庫表圖3 數(shù)據(jù)庫關(guān)系圖 2.2 數(shù)據(jù)庫表說明
|
Static_User字段名
|
詳細解釋
|
類型
|
備注
|
UserID
|
路線編號
|
varchar(20)
|
PK
|
UserName
|
用戶名稱
|
varchar(20)
|
|
UserPwd
|
用戶密碼
|
varchar(20)
|
|
LastSignTime
|
最后登陸時間
|
datatime
|
|
SignState
|
用戶登陸狀態(tài)標(biāo)記
|
int
|
|
TickeID
|
驗證票記錄編號
|
varchar(128)
|
|
|
|
|
|
Static_Role
Static_User字段名
|
詳細解釋
|
類型
|
備注
|
RoleID
|
角色編號
|
varchar(20)
|
PK
|
RoleName
|
角色名稱
|
varchar(20)
|
|
RoleNote
|
角色信息描述
|
varchar(20)
|
|
|
|
|
|
Static_User_Role
Static_User字段名
|
詳細解釋
|
類型
|
備注
|
UserRoleID
|
用戶角色編號
|
varchar(20)
|
PK
|
UserID
|
用戶編號
|
varchar(20)
|
FK
|
RoleID
|
角色編號
|
varchar(20)
|
FK
|
UserRoleNote
|
用戶角色信息描述
|
varchar(20)
|
|
|
|
|
|
Static_Permission
Static_User字段名
|
詳細解釋
|
類型
|
備注
|
PermissionID
|
編號
|
varchar(20)
|
PK
|
PermissionName
|
權(quán)限名稱
|
varchar(20)
|
|
PermissionNote
|
全息信息描述
|
varchar(20)
|
|
|
|
|
|
Static_Role_Permission
Static_User字段名
|
詳細解釋
|
類型
|
備注
|
RolePermissionID
|
角色權(quán)限編號
|
varchar(20)
|
PK
|
RoleID
|
角色編號
|
varchar(20)
|
FK
|
PermissionID
|
權(quán)限編號
|
varchar(20)
|
FK
|
RolePermissionNote
|
角色權(quán)限信息描述
|
varchar(20)
|
|
|
|
|
|
對 SQL 數(shù)據(jù)庫執(zhí)行自定義身份驗證和授權(quán),。在這種情況中,,應(yīng)向服務(wù)傳遞自定義憑據(jù)(如用戶名和密碼),并讓服務(wù)自己處理身份驗證和授權(quán),。 將額外的信息連同請求一起傳遞給 XML Web 服務(wù)的簡便方法是通過 SOAP 標(biāo)頭,。為此,需要在服務(wù)中定義一個從 SOAPHeader 派生的類,然后將服務(wù)的公共字段聲明為該類型,。這在服務(wù)的公共合同中公開,,并且當(dāng)從 WebServiceUtil.exe 創(chuàng)建代理時可由客戶端使用,如下例所示:
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;
...
}
服務(wù)中的每個 WebMethod 都可以使用 SoapHeader 自定義屬性定義一組關(guān)聯(lián)的標(biāo)頭,。默認情況下,,標(biāo)頭是必需的,但也可以定義可選標(biāo)頭,。SoapHeader 屬性指定公共字段的名稱或者 Client 或 Server 類的屬性(本標(biāo)題中稱為 Headers 屬性),。在為輸入標(biāo)頭調(diào)用方法前,WebService 設(shè)置 Headers 屬性的值,;而當(dāng)方法為輸出標(biāo)頭返回時,,WebService 檢索該值。
[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;
}
然后,,客戶端在調(diào)用要求標(biāo)頭的方法之前,,直接在代理類上設(shè)置標(biāo)頭,如下面的示例所示:
HeaderService h = new HeaderService();
AuthHeader myHeader = new AuthHeader();
myHeader.Username = "username";
myHeader.Password = "password";
h.AuthHeader = myHeader;
String result = h.SecureMethod();
CallContext提供與執(zhí)行代碼路徑一起傳送的屬性集,,CallContext是類似于方法調(diào)用的線程本地存儲的專用集合對象,,并提供對每個邏輯執(zhí)行線程都唯一的數(shù)據(jù)槽。數(shù)據(jù)槽不在其他邏輯線程上的調(diào)用上下文之間共享,。當(dāng) CallContext 沿執(zhí)行代碼路徑往返傳播并且由該路徑中的各個對象檢查時,,可將對象添加到其中。當(dāng)對另一個 AppDomain 中的對象進行遠程方法調(diào)用時,,CallContext 類將生成一個與該遠程調(diào)用一起傳播的 LogicalCallContext 實例,。只有公開 ILogicalThreadAffinative 接口并存儲在 CallContext 中的對象被在 LogicalCallContext 中傳播到 AppDomain 外部。不支持此接口的對象不在 LogicalCallContext 實例中與遠程方法調(diào)用一起傳輸,。
CallContext.SetData方法存儲給定對象并將其與指定名稱關(guān)聯(lián),,CallContext.GetData方法從 CallContext 中檢索具有指定名稱的對象。
下面的代碼示例說明如何使用 SetData 方法將主體和標(biāo)識對象傳輸?shù)竭h程位置以進行標(biāo)識,。
public class ClientClass {
public static void
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);
}
}
下面的代碼示例說明如何使用 GetData 方法將主體和標(biāo)識對象傳輸?shù)竭h程位置以進行標(biāo)識,。
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 + ".";
}
}
WebService端代碼主要進行對數(shù)據(jù)庫的操作,建立起Client操作數(shù)據(jù)庫所需要的方法,,供Client的端調(diào)用,。
1)class UserInfoMng() 用戶信息管理類,其中包括方法:
l CreateUserInfo(string UserName string UserPwd) 建立用戶信息,,調(diào)用存儲過程CreateUserInfo(@UserName,@UserPwd)
l ModifyUserInfo(string UserName string UserPwd) 修改用戶信息,,調(diào)用存儲過程ModifyUserInfo(@UserName,@UserPwd)
l DeleteUserInfo() 刪除用戶信息,調(diào)用存儲過程DeleteUserInfo
(@UserID)
2)class UserAuthentication() 用戶認證類,,用來實現(xiàn)用戶角色,、權(quán)限的設(shè)置,,包括方法:
l CreatePermissionInfo(string PermissionName string Permissi-
-onNote) 建立權(quán)限信息,調(diào)用存儲過程CreatePermissionInfo
(@PermissionName,@PermissionNote)
l CreateRoleInfo(string RoleName string RoleNote) 建立角色信息,,調(diào)用存儲過程CreateRoleInfo(@RoleName,@RoleNote)
l DeleteRoleInfo() 刪除角色信息,,調(diào)用存儲過程DeleteRoleInfo
(@RoleID)
l GrantUserRole(string UserID string RoleID string UserRoleNote) 授予用戶角色,調(diào)用存儲過程GrantUserRole(@UserID,@RoleID,
@UserRoleNote)
l DeleteUserRole() 刪除用戶角色,,調(diào)用存儲過程DeleteUserRole
(@UserRoleID)
l GrantRolePermission(string RoleID string PermissionID string RolePermissionNote) 授予角色權(quán)限,,調(diào)用存儲過程GrantRolePermission(@RoleID,@PermissionID,@RolePermissionNote)
l DeleteRolePermission() 刪除授予的角色權(quán)限,調(diào)用存儲過程
DeleteRolePermission(@RolePermissionID)
Client端調(diào)用WebService方法來進行數(shù)據(jù)庫訪問,,Client端代碼設(shè)計主要實現(xiàn)界面的功能,,包括:權(quán)限設(shè)置、用戶管理,、用戶授權(quán)管理和用戶認證管理
1)權(quán)限設(shè)置
class PermissionInfoMng() 用戶權(quán)限信息管理類,,包括方法:
l CreatePermissionInfo() 建立權(quán)限信息
2)用戶管理
class UserInfoMng() 用戶信息管理類,包括方法:
l CreateUserInfo() 建立用戶信息
l ModifyUserInfo() 修改用戶信息
l DeleteUserInfo() 刪除用戶信息
3)用戶授權(quán)管理
class RoleInfoMng() 角色信息管理類,,包括方法:
l CreateRoleInfo() 建立角色信息
l DeleteRoleInfo() 刪除角色信息
class UserRoleMng() 用戶角色管理類,,包括方法:
l GrantUserRole() 授予用戶角色
l DeleteUserRole() 刪除用戶角色
class RolePermissionMng() 角色權(quán)限管理類,包括方法
l GrantRolePermission() 授予角色權(quán)限
l DeleteRolePermission() 刪除角色權(quán)限
4)用戶認證管理
class Authentication() 用戶認證類,,包括方法:
l Login(string UserName string UserPwd) 用戶登陸認證,,用戶認證通過分配給用戶一個TicketID,否則TicketID則為null
l Logout() 用戶正常退出
l ExceptionLogout() 用戶異常退出
|