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