明輝手游網(wǎng)中心:是一個(gè)免費(fèi)提供流行視頻軟件教程、在線(xiàn)學(xué)習(xí)分享的學(xué)習(xí)平臺(tái)!

基于用戶(hù)的安全策略在B/S中的完成(2)

[摘要]2 菜單管理 菜單管理主要包括兩部分的內(nèi)容,菜單項(xiàng)的編輯維護(hù)與根據(jù)當(dāng)前登陸用戶(hù)的權(quán)限進(jìn)行菜單的生成。 菜單的編輯維護(hù)就是指對(duì)菜單表的維護(hù)。因?yàn)楸容^簡(jiǎn)單,在此不做詳細(xì)說(shuō)明,只是要注意以下三個(gè)問(wèn)題: 第一、菜單編號(hào)與權(quán)限位數(shù)的生成。因?yàn)椴藛雾?xiàng)是可以刪除的,如果新增菜單項(xiàng)獲取編號(hào)與權(quán)限位數(shù)時(shí)只是在最大的...

2 菜單管理

菜單管理主要包括兩部分的內(nèi)容,菜單項(xiàng)的編輯維護(hù)與根據(jù)當(dāng)前登陸用戶(hù)的權(quán)限進(jìn)行菜單的生成。

菜單的編輯維護(hù)就是指對(duì)菜單表的維護(hù)。因?yàn)楸容^簡(jiǎn)單,在此不做詳細(xì)說(shuō)明,只是要注意以下三個(gè)問(wèn)題:

第一、菜單編號(hào)與權(quán)限位數(shù)的生成。因?yàn)椴藛雾?xiàng)是可以刪除的,如果新增菜單項(xiàng)獲取編號(hào)與權(quán)限位數(shù)時(shí)只是在最大的編號(hào)上增1的話(huà),必須會(huì)導(dǎo)致編碼資源的浪費(fèi),特別是權(quán)限位數(shù),只有100位,如果由于跳號(hào)而導(dǎo)致了編碼資源的浪費(fèi),必然導(dǎo)致新功能模塊無(wú)編碼資源可用。所以,在添加新菜單項(xiàng)是必須要解決跳號(hào)的問(wèn)題。請(qǐng)看以下取編號(hào)與權(quán)限位數(shù)的語(yǔ)句:

select min(CDBH)+1 from CDB where CDBH+1 not in(select CDBH from CDB)

select min(QXWS)+1 from CDB where QXWS+1 not in(select QXWS from CDB)

我們只要保證對(duì)于菜單維護(hù)本身的這個(gè)功能模塊給它分配菜單編號(hào)為1,權(quán)限位數(shù)為1的話(huà),就能夠保證在任何情況下新增菜單項(xiàng)時(shí)菜單編號(hào)與權(quán)限位數(shù)不會(huì)跳號(hào),編碼資源能夠得到充分利用。因?yàn)椴藛尉S護(hù)本身這個(gè)菜單項(xiàng)在通常情況下是不會(huì)被刪除的。

第二、入口路徑是指進(jìn)入本功能模塊的第一個(gè)頁(yè)面的連接地址,請(qǐng)注意路徑的相對(duì)性問(wèn)題。

第三、相關(guān)文件是指完成本功能模塊的頁(yè)面組合。一般情況下,一個(gè)菜單項(xiàng)下連接一個(gè)功能模塊,要完成該功能模塊的功能可能需要若干個(gè)ASP頁(yè)面。例如,菜單項(xiàng)1的入口路徑是../menu1.asp,還要以下三個(gè)頁(yè)面,menu11.asp, menu12.asp, menu13.asp,則相關(guān)文件的內(nèi)容是指meunu1.asp, menu11.asp,menu12.asp,menu13.asp這個(gè)字符串序例。該項(xiàng)的主要作用是為了安全檢查而設(shè)置的,也就是頁(yè)面在系統(tǒng)中的注冊(cè)過(guò)程。

根據(jù)當(dāng)前登陸用戶(hù)的權(quán)限進(jìn)行菜單生成時(shí)有一個(gè)關(guān)鍵的會(huì)話(huà)變量:Session("YHQX"),該變量在后面將要進(jìn)行描述的安全檢查過(guò)程中生成,一直保存到用戶(hù)退出系統(tǒng)或者會(huì)話(huà)超時(shí)失效時(shí)為止。里面的內(nèi)容就是100位的當(dāng)前登陸用戶(hù)的權(quán)限字符串。根據(jù)該變量生成菜單的過(guò)程如下:

<% sql="select * from CDB where FCDBH=0 order by CDBH"

set Rs=Conn.execute(sql)

'取得菜單表中的所有有子菜單的父菜單

'遍歷父菜單

do while not Rs.eof

SubMenuNum=0

sql="select QXWS from CDB where FCDBH="&Rs("CDBH")&" order by CDBH"

set Rs1=Conn.execute(sql)

'獲取當(dāng)前父菜單下的所有子菜單

'遍歷當(dāng)前父菜單下的子菜單

do while not Rs1.eof

if Mid(Session("YHQX"),Rs1("QXWS"),1)=1 then

SubMenuNum=SubMenuNum+1

'如果當(dāng)前用戶(hù)有當(dāng)前子菜單的權(quán)限,則子菜單的個(gè)數(shù)加上1

end if

Rs1.movenext

loop

Rs1.close

set Rs1=nothing

if SubMenuNum>0 then

'如果當(dāng)前用戶(hù)的當(dāng)前父菜單的下子菜單個(gè)數(shù)大于零則生成該父菜單

if Rs.bof then FirstMenu=Rs("CDBH") end if

MenuNum=Rs("CDBH")

ParentName=Rs("CDMC")

response.write "<!-- "&ParentName&"父菜單 -->"

%>

<menu class=parent name=<%=ParentName%> url=<%=Rs("RKLJ")%> target= mainFrame >

'菜單的形式與樣式根據(jù)需要自己調(diào)整,這里采用泛指方式

<%

response.write "<!-- "&ParentName&"子菜單 -->"

sql="select * from CDB where FCDBH="&MenuNum&" order by CDBH"

set Rs1=Conn.execute(sql)

'查找該父菜單下的所有子菜單

do while not Rs1.eof

if Mid(Session("YHQX"),Rs1("YHQX"),1)=1 then

%>

<menu class=child name=<%=Rs("CDMC")%> url=<%=Rs("RKLJ")%> target= mainFrame ><br>

'菜單的形式與樣式根據(jù)需要自己調(diào)整,這里采用泛指方式

<%

end if

Rs1.movenext

loop

Rs1.close

set Rs1=nothing

end if

Rs.movenext

loop

Rs.close

set Rs=nothing

%>

由于本系統(tǒng)只有兩級(jí)菜單,所以沒(méi)有牽涉到菜單遞歸調(diào)用生成的問(wèn)題。如果要實(shí)現(xiàn)的話(huà)必須把菜單生成過(guò)程定義成函數(shù)形式,才能進(jìn)行遞歸調(diào)用,在此不做詳細(xì)討論。


3 權(quán)限分配

權(quán)限的分配由用戶(hù)組權(quán)限分配與用戶(hù)的權(quán)限分配兩部分組成。是將具體的菜單與用戶(hù)組或者用戶(hù)關(guān)聯(lián)的過(guò)程。

首先看用戶(hù)組的添加界面如下:

<form name="zjyhz" method="post" action="yhzbmb_zj.asp" onsubmit="return checkinput(this)"> <!-- 調(diào)用輸入檢驗(yàn)函數(shù),并生成權(quán)限字符串-->

<input type="hidden" name="action" value="zjyhz">

<table cellpadding="0" cellspacing="0" width="100%">

<tr>

<td><fieldset align="center"><legend>增加用戶(hù)組

</legend>

<input type="hidden" name="DQDWDM" value="<%=DQDWDM%>"><!--由前一頁(yè)傳入,當(dāng)前單位編碼-->

用戶(hù)組名稱(chēng):<input type="text" name="yhzmc" size="50" maxlength="50" ><br><br>

設(shè)置用戶(hù)組權(quán)限:<br>

<table width="100%" border="0" cellpadding="0" cellspacing="0">

<tr>

<td width="150">

<input type="hidden" name="yhzqx">

<select id="allqx" size=10 style='width:150'>

<%

sql="SELECT CDMC, QXWS FROM CDB where FCDBH<>0 ORDER BY CDBH"

set Rs1=Conn.exece(sql)

'取得所有子菜單

%>

<%do while not Rs1.eof

if Mid(Session("YHQX"),Rs1("QXWS"),1)=1 then

'但是只有當(dāng)前用戶(hù)擁有的權(quán)限它才能將該權(quán)限賦給它所新建立的用戶(hù)組,有利的保證了安全性,只能繼承,不能超越,將滿(mǎn)足條件的菜單項(xiàng)顯示在例表框中,待用戶(hù)選擇。

%>

<option value="<%=Rs1("QXWS")%>"><%=Rs1("CDMC")%></option>

<%

end if

Rs1.movenext

loop

Rs1.close

set Rs1=nothing

%>

</select>

</td>

<td width="30" align="center">

<input type="button" name="Submit3" value=" -> " class="addbutton" onclick="MoveItem(document.zjyhz.allqx,document.zjyhz.selectqx)">

<input type="button" name="Submit32" value=" <- " class="addbutton" onclick="MoveItem(document.zjyhz.selectqx,document.zjyhz.allqx)">

</td>

<td width="*">

<!—已經(jīng)選好的菜單項(xiàng)的例表框-->

<select id="selectqx" size=10 style='width:150'>

</select>

</td>

</tr>

</table><br>

<input type="submit" name="Submit" value="增 加">

<input type="reset" name="Submit2" value="清 空">

<input type="button" name="Submit2" value="放 棄" onclick="location.href='yhzbmb.asp?DQDWDM=<%=DQDWDM%>'">

</fieldset></td>

</tr>

</table>

</form>

<!—以下javascript函數(shù)實(shí)現(xiàn)界面的操作以及輸入驗(yàn)證工作-->

<script language="javascript">

//在一個(gè)例表框中插入一項(xiàng)

function InsertItem(ListObj,ListText,ListValue)

{ len=ListObj.length;

ListObj.options[len] = new Option(ListText,ListValue);}

//將例表框中指定的項(xiàng)刪除

function DeleteItem(ListObj,DeleteIndex)

{ ListObj.options[DeleteIndex] = null;}

//將一項(xiàng)從一個(gè)例表框移到另一個(gè)例表框

function MoveItem(srcListObj,decListObj)

{ if(srcListObj.selectedIndex!=-1)

{ ListValue=srcListObj.options[srcListObj.selectedIndex].value; ListText=srcListObj.options[srcListObj.selectedIndex].text;

DeleteItem(srcListObj,srcListObj.selectedIndex);

for(i=0;i<decListObj.length;i++)

{ if(ListValue==decListObj.options[i].value) return}

InsertItem(decListObj,ListText,ListValue);}

}

//輸入校驗(yàn)并生成新用戶(hù)組權(quán)限字符串

function checkinput(FormHandle)

{ if(FormHandle.yhzmc.value=="")

{ alert("用戶(hù)組名稱(chēng)不能為空!");

FormHandle.yhzmc.focus();

return false; }

var strYhzqx="0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";

var beforebit,afterbit

for(i=0;i<FormHandle.selectqx.length;i++)

{ beforebit=strYhzqx.substr(0,FormHandle.selectqx.options[i].value-1);

afterbit=strYhzqx.substr(FormHandle.selectqx.options[i].value,99);

strYhzqx=beforebit+"1"+afterbit; }

if(strYhzqx.length!=100) alert("bit error");

FormHandle.yhzqx.value=strYhzqx;

return true;}

</script>

以上FORM提交后寫(xiě)入數(shù)據(jù)庫(kù)就完成了用戶(hù)組的添加,這里也有用戶(hù)組編號(hào)可能跳號(hào)的問(wèn)題,可以用上面已經(jīng)描述過(guò)的方法加以解決。當(dāng)對(duì)用戶(hù)組的權(quán)限進(jìn)行編輯時(shí),我們必須將屬于當(dāng)前登陸用戶(hù)但不屬于該用戶(hù)組的權(quán)限顯示在一個(gè)例表框中,屬于該用戶(hù)組的權(quán)限顯示在別一個(gè)例表框中,用以下語(yǔ)句分別實(shí)現(xiàn):

<select id="allqx" size=10 style='width:150'>

<%sql="SELECT CDMC, QXWS FROM CDB where FCDBH<>0 ORDER BY CDBH"

set Rs1=Conn.execute(sql) %>

<%do while not Rs1.eof

if Mid(Session("YHQX"),Rs1("QXWS"),1)=1 then

if Mid(Rs("YHZQX"),Rs1("QXWS"),1)=0 then

'Rs("YHZQX")就是需要編輯的用戶(hù)組的權(quán)限,在更上面的語(yǔ)句中進(jìn)行初始化%>

<option value="<%=Rs1("QXWS")%>"><%=Rs1("CDMC")%></option>

<% end if end if Rs1.movenext loop Rs1.close set Rs1=nothing %>

</select>

<select id="selectqx" size=10 style='width:150'>

<%yhzqx=trim(Rs("YHZQX"))

'Rs("YHZQX")就是需要編輯的用戶(hù)組的權(quán)限,在更上面的語(yǔ)句中進(jìn)行初始化

for i=1 to len(yhzqx)

if(mid(yhzqx,i,1)="1") then

sql="select CDMC from CDB where QXWS="&i

set Rs1=Conn.execute(sql)

if Not Rs1.eof then%>

<option value="<%=i%>"><%=Rs1("CDMC")%></option>

<%end if Rs1.close set Rs1=nothing end if next Rs1.close set Rs1=nothing %>

</select>

其它操作過(guò)程與添加時(shí)基本一致。

用戶(hù)的操作過(guò)程與用戶(hù)組的操作過(guò)程基本上也是一樣的,所用到的代碼也大致相同,不過(guò)還是有幾個(gè)要注意的問(wèn)題:

第一、添加用戶(hù)時(shí)不需要指定用戶(hù)的權(quán)限,只要指定該用戶(hù)所屬的用戶(hù)組即可,用戶(hù)權(quán)限自動(dòng)從用戶(hù)組繼承。當(dāng)然添加完了也可以對(duì)用戶(hù)組的權(quán)限進(jìn)行修改,為了保障安全,修改的范圍也只限當(dāng)前登陸的用戶(hù)權(quán)限范圍內(nèi)。實(shí)現(xiàn)如上所述相同。

第二、用戶(hù)密碼的存貯,建議不要存貯為明碼,請(qǐng)加密存貯,在本系統(tǒng)中采取了不可逆轉(zhuǎn)的加密算法,即使知道了加密算法與加密后的結(jié)果,也不可能還原為原始密碼,有利的保障了安全性。

第三、每當(dāng)在用戶(hù)組中添加一個(gè)用戶(hù)時(shí)用戶(hù)組表的用戶(hù)個(gè)數(shù)就會(huì)增加1,當(dāng)然刪除一個(gè)用戶(hù)也會(huì)使用該組的用戶(hù)個(gè)數(shù)減1。

第四、用戶(hù)所屬的用戶(hù)組可以修改,修改后用戶(hù)的權(quán)限與新屬用戶(hù)組的權(quán)限一樣。

4 安全檢查

安全檢查指登陸的安全檢查與訪(fǎng)問(wèn)每個(gè)頁(yè)面時(shí)的安全檢查兩個(gè)方面。

登陸時(shí)的安全檢查指驗(yàn)證用戶(hù)名與密碼,如果驗(yàn)證通過(guò),將該用戶(hù)的用戶(hù)權(quán)限存貯于會(huì)話(huà)變量Session("YHQX")中,以利于隨時(shí)檢驗(yàn)。然后引導(dǎo)入主界面,并根據(jù)Session("YHQX")生成系統(tǒng)菜單。

我們重點(diǎn)說(shuō)一下訪(fǎng)問(wèn)每個(gè)頁(yè)面時(shí)的安全檢查。大家都知道,與C/S程序不同,某個(gè)菜單沒(méi)有顯示出來(lái),就并不代表用戶(hù)沒(méi)有辦法訪(fǎng)問(wèn)該菜單項(xiàng)的功能,因?yàn)橛脩?hù)可以通過(guò)直接輸入U(xiǎn)RL訪(fǎng)問(wèn)到該功能模塊,所以必須在訪(fǎng)問(wèn)每個(gè)頁(yè)面是也要提供一個(gè)權(quán)限控制機(jī)制,防止用戶(hù)越權(quán)使用。我們用如下代碼實(shí)現(xiàn)了訪(fǎng)問(wèn)頁(yè)面時(shí)的權(quán)限檢驗(yàn):

<% ScriptName=Request.ServerVariables("SCRIPT_NAME")

'取得當(dāng)次請(qǐng)求的URL

for i=len(ScriptName) to 1 step -1

if Mid(ScriptName,i,1)="/" then exit for

next

ScriptName=Mid(ScriptName,i+1,len(ScriptName)-i)

'分離出請(qǐng)求的ASP頁(yè)面文件名

sql="select 權(quán)限位數(shù) from 菜單權(quán)限表 where




相關(guān)文件 like '%"&ScriptName&"%'"

set Rs1=Conn.execute(sql)

'查找其屬于哪一位權(quán)限,根據(jù)上面所述的相關(guān)文件進(jìn)行查找

if Rs1.eof and Rs1.bof then

response.write "非法訪(fǎng)問(wèn)!"&ScriptName&"還沒(méi)有進(jìn)行注冊(cè),請(qǐng)通知系統(tǒng)管理員進(jìn)行注冊(cè)!"

Rs1.close

set Rs1=nothing

response.end

end if

'比較當(dāng)前用戶(hù)的權(quán)限,看是否有訪(fǎng)問(wèn)當(dāng)前頁(yè)面的權(quán)利

Qxbit=Mid(Session("YHQX"),Rs1(0),1)

if Qxbit="" then

response.write "非法訪(fǎng)問(wèn)!"&"<br>權(quán)限位數(shù)錯(cuò)誤,可能是由于您長(zhǎng)時(shí)間沒(méi)有操作而超時(shí)退出!<br>請(qǐng)重新登陸或聯(lián)系管理員!"

Rs1.close

set Rs1=nothing

response.end

end if

if Qxbit="0" then

response.write "非法訪(fǎng)問(wèn)!"&"您沒(méi)有訪(fǎng)問(wèn)此頁(yè)的權(quán)限!"

Rs1.close

set Rs1=nothing

response.end

end if

Rs1.close

set Rs1=nothing

%>

將該文件存為validate.inc

然后在系統(tǒng)中的每個(gè)文件的最頂部用如下語(yǔ)句包含進(jìn)去:

<!--#include file="validate.inc"-->

這樣一來(lái),就實(shí)現(xiàn)了頁(yè)面級(jí)的權(quán)限檢查,并且非常方便。甚至,與一些WEB服務(wù)器配合,這個(gè)執(zhí)行過(guò)程可以自動(dòng)完成,并不需要在系統(tǒng)的每一個(gè)文件頂部包含validate.inc文件,WEB服務(wù)器在調(diào)用每一個(gè)頁(yè)面前會(huì)自動(dòng)將validate.inc包含到文件頂部。

在需要開(kāi)發(fā)基于用戶(hù)的安全策略的B/S應(yīng)用時(shí),首先將以上所述的框架搭建起來(lái),然后再單獨(dú)開(kāi)發(fā)各個(gè)功能模塊,然后用提供的菜單管理功能,將功能模塊以搭積木的方式添加進(jìn)來(lái),這樣非常方便,也利于團(tuán)隊(duì)的協(xié)作開(kāi)發(fā)。由于有開(kāi)放的菜單與統(tǒng)一的權(quán)限控制策略,所開(kāi)發(fā)的應(yīng)用也能夠很好的與用戶(hù)本身所擁有的B/S應(yīng)用或者其它廠(chǎng)商的B/S應(yīng)用集成在一起,為用戶(hù)提供統(tǒng)一的用戶(hù)操作界面與權(quán)限控制體系,這將使產(chǎn)品非常有竟?fàn)幜ΑT谖覀冮_(kāi)發(fā)的稅務(wù)系統(tǒng)后臺(tái)管理系統(tǒng)中,利用此框架,實(shí)現(xiàn)了與用戶(hù)方和第三方廠(chǎng)商應(yīng)用的集成。