在pb實現(xiàn)一般管理系統(tǒng)的時候,我們會遇到這樣一種情況,作為一個系統(tǒng),可以分為若干個子系統(tǒng),有多個操作員對它進(jìn)行操作,每個操作員對各個子系統(tǒng)的權(quán)限不同,甚至在同一子系統(tǒng)中,操作員對各個菜單項的操作權(quán)限也不一樣,更細(xì)一點,不同的操作員對于同一窗口中某一按鈕的操作權(quán)限也是不一樣的,那么,怎樣較好地實現(xiàn)對不同用戶細(xì)化到某個按鈕的權(quán)限控制呢?筆者在進(jìn)行一個系統(tǒng)的開發(fā)過程當(dāng)中,積累了一些心得,與大家探討一下。 首先,怎樣使得一個操作員不能對他不具權(quán)限的菜單項或按鈕進(jìn)行操作呢,我們當(dāng)然沒有必要為不同的用戶制作不同的菜單項或窗口(當(dāng)然這也不失為一種方法),考慮到菜單項和按鈕的visible和enabled屬性,我們自然想到,設(shè)置這兩個屬性便可以完成上面的要求,比如 m_1.m_2.visible=false 或者 cb_1.enabled=false 菜單不可見了,操作員自然就不可操作了。 其次,對于一個多用戶的系統(tǒng),我們自然需要用一個表來存放基本的用戶信息,其中要包括用戶登錄系統(tǒng)的用戶名、密碼,如果要進(jìn)行權(quán)限的分級控制,還需要一些字段來存放有關(guān)權(quán)限的信息,有些成品系統(tǒng)中是這樣做的,不過它們將每個需要進(jìn)行控制的菜單項均用一個字段來表示,這樣做不太好,萬一設(shè)計一個權(quán)限控制比較細(xì)的系統(tǒng)時,這樣做的可行性便不好,其實,對與某個菜單項或其他控件,進(jìn)行權(quán)限控制時,狀態(tài)只有兩個,true or false,完全可以用一位二進(jìn)制數(shù)0或1來表示,我們可以將一個子系統(tǒng)中所有需要進(jìn)行權(quán)限控制的項組合成一個二進(jìn)制串,每四個二進(jìn)制數(shù)轉(zhuǎn)化成一個字符(可以是 "0","1","2"...."a","b","c","d","e","f"),再保存在表中,這樣我們來算一下,如果一個子系統(tǒng)中有64個項需要進(jìn)行權(quán)限控制,則只需要一個 64/4=16 位的字符類型的字段即可以表示,而不像過去那樣需要64個字段來分別標(biāo)記。 好了,第一步存放的問題解決了,那么怎樣根據(jù)這樣的一個標(biāo)記權(quán)限的字符串來設(shè)置各個菜單項或其他控件的visible 或enabled屬性呢?我注意到,pb中菜單項和其它控件都有一個tag屬性,而這個屬性我們一般不太會用到它,我們可以用tag屬性來存放一個數(shù)字,這個數(shù)字標(biāo)示了該控件在權(quán)限控制字段的那個二進(jìn)制串中表示該控件的訪問權(quán)限的0/1的位置,舉個例子,有一個權(quán)限控制二進(jìn)制串'01001111010....',菜單項"打開文件"的tag為7,則在該二進(jìn)制串中第7位"1"便標(biāo)記了當(dāng)前用戶對"打開文件"的控制權(quán)限為"1". 當(dāng)一個用戶登錄系統(tǒng)時,在通過了密碼驗證后,將他對該系統(tǒng)的權(quán)限控制字段的字符串讀到一個全局變量中,將該字符串恢復(fù)為0、1串,對于每個需要進(jìn)行權(quán)限控制的項,依次根據(jù)其tag記錄的相應(yīng)位置的0或1設(shè)置visible或enabled屬性,便可以完成對權(quán)限的管理。 當(dāng)然,要注意的是,有些控件的權(quán)限設(shè)置并不是在一進(jìn)入系統(tǒng)后就進(jìn)行的,而是推遲到該控件被調(diào)用時才進(jìn)行。 下面給出了一個例子,來說明上面的論述。 有以下3個菜單項和2個按鈕需要控制 3個菜單項名稱分別為: m_a.m_h1.m_m1 m_a.m_h1.m_m2 m_a.m_h1.m_m3 以上3個菜單項的tag設(shè)置為 1-3 2個按鈕位于兩個窗口中 cb_1 位于w_1中 cb_2 位于w_2中 以上2個按鈕的tag設(shè)置為4,5 這樣,需要5位來表示他們的訪問權(quán)限。 函數(shù)getbin用來進(jìn)行從"0","1"...,"a"..."f"到四位二進(jìn)制串的轉(zhuǎn)換 getbin(string s_ch) returns string string s_out,s_temp integer i_len integer i string temp i_len=len(s_ch) if i_len=0 or isnull(s_ch) then s_out="0" end if temp="" s_temp="" for i=1 to i_len temp=mid(s_ch,i,1) choose case lower(temp) case "a" s_temp="1010" case "b" s_temp="1011" case "c" s_temp="1100" case "d" s_temp="1101" case "e" s_temp="1110" case "f" s_temp="1111" case "0" s_temp="0000" case "1" s_temp="0001" case "2" s_temp="0010" case "3" s_temp="0011" case "4" s_temp="0100" case "5" s_temp="0101" case "6" s_temp="0110" case "7" s_temp="0111" case "8" s_temp="1000" case "9" s_temp="1001" case else s_temp="0000" end choose s_out=s_out+s_temp s_temp="" next return s_out 定義一個全局變量s_admin用來存放該用戶登錄后的權(quán)限信息: string s_temp select rights into :s_temp where user=:username and password=:userpassword; s_admin=getbin(s_temp) //s_admin存放的是已經(jīng)轉(zhuǎn)化好的權(quán)限信息。
定義一個權(quán)限函數(shù)check來完成從 0、1 到true、false 的轉(zhuǎn)換。 check(string menutag) returns boolean string s_temp s_temp=mid(s_admin,integer(menutag),1) //s_admin為全局變量 if isnull(s_temp) or s_temp="1" then return true else return false end if 假設(shè)w_main為登錄后的主窗口,它的菜單為m_a 則在w_main的open事件中這樣寫: m_a.m_h1.m_m1.enabled=check(m_a.m_h1.m_m1.tag) m_a.m_h1.m_m2.enabled=check(m_a.m_h1.m_m2.tag) m_a.m_h1.m_m3.enabled=check(m_a.m_h1.m_m3.tag) 在w_1的open事件中: cb_1.enabled=check(cb_1.tag) 同樣,在w_2的open事件中 cb_2.enabled=check(cb_2.tag) 這樣就可以完成對上述5項的控制。 當(dāng)然,這種方法在需要控制的項很多時(達(dá)到幾十項)的效果才比較明顯。 以上論述了權(quán)限控制的實現(xiàn),在多用戶系統(tǒng)中,還需要有對用戶權(quán)限的設(shè)置功能,這個和上面 時一個相反的過程,相信讀者在看完上面的內(nèi)容之后一定會掌握權(quán)限設(shè)置的做法,這里就不再冗述了。