1 設計思路
為了設計一套具有較強可擴充性的使用者認證管理,需要建立使用者、角色和權限等資料庫表,并且建立之間的關系,具體實作如下。
使用者僅僅是純粹的使用者,用來記錄使用者相關資訊,如使用者名、密碼等,權限是被分離出去了的。使用者(user)要擁有對某種資源的權限,必須通過角色(role)去關聯。
使用者通常具有以下屬性:
ü 編号,在系統中唯一。
ü 名稱,在系統中唯一。
ü 使用者密碼。
ü 注釋,描述使用者或角色的資訊。
角色是使用權限的基本機關,擁有一定數量的權限,通過角色賦予使用者權限,通常具有以下屬性:
ü 注釋,描述角色資訊
權限指使用者根據角色獲得對程式某些功能的操作,例如對檔案的讀、寫、修改和删除功能,通常具有以下屬性:
ü 注釋,描述權限資訊
一個使用者(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 使用者“李四”被配置設定到角色“排程人員”
從該關系表可以看出,使用者所擁有的特定資源可以通過使用者角色來關聯。
一個角色(role)可以擁有多個權限(permission),同樣一個權限可配置設定給多個角色。例如:
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 角色“監控人員”具有權限“察看監控”
由以上例子中的角色權限關系可以看出,角色權限可以建立角色和權限之間的對應關系。
使用者權限系統的核心由以下三部分構成:創造權限、配置設定權限和使用權限。
第一步由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)獲得使用者對子產品的使用權限。
當使用者通過驗證後,由系統自動生成一個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 資料庫設計
圖3 資料庫關系圖
static_user
static_user字段名
詳細解釋
類型
備注
userid
路線編号
varchar(20)
pk
username
使用者名稱
userpwd
使用者密碼
lastsigntime
最後登陸時間
datatime
signstate
使用者登陸狀态标記
int
tickeid
驗證票記錄編号
varchar(128)
static_role
roleid
角色編号
rolename
角色名稱
rolenote
角色資訊描述
static_user_role
userroleid
使用者角色編号
使用者編号
fk
userrolenote
使用者角色資訊描述
static_permission
permissionid
編号
permissionname
權限名稱
permissionnote
全息資訊描述
static_role_permission
rolepermissionid
角色權限編号
權限編号
rolepermissionnote
角色權限資訊描述
3 .net技術概要
對 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();
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");
//extract the returned data from the call context
logicalcallcontextdata returneddata =
(logicalcallcontextdata)callcontext.getdata("test data");
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)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 詳細代碼設計
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)
client端調用webservice方法來進行資料庫通路,client端代碼設計主要實作界面的功能,包括:權限設定、使用者管理、使用者授權管理和使用者認證管理
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() 使用者正常退出
l exceptionlogout() 使用者異常退出