控制客戶端訪問是開發(fā)一個(gè)基于B/S的架構(gòu)的系統(tǒng)的開發(fā)者必須考慮的問題。JSP或SERVLET規(guī)范的基于配置文件的安全策略對(duì)資源的控制是以文件為單位的,即只可以定義某個(gè)視圖全部可以或全部不能被訪問。一個(gè)比較復(fù)雜的系統(tǒng)往往要要求對(duì)視圖的一部分(如JSP頁面里的一個(gè)按鈕)提供訪問控制,只允許被某種角色的用戶訪問。如果采用可編程的安全策略,因?yàn)閷?duì)用戶角色和操作的定義在開發(fā)時(shí)不能定義,而且這種策略加大了程序員的工作量,它可能不是一種好的辦法。
我采用定制標(biāo)簽庫和和配置文件來解決這個(gè)問題:把要權(quán)限控制的JSP頁面元素如BUTTON,作為標(biāo)簽的內(nèi)容。為受保護(hù)的內(nèi)容起一個(gè)唯一的名稱,把這個(gè)名稱作為標(biāo)簽的一個(gè)屬性。某個(gè)角色對(duì)某個(gè)頁面元素或一組頁面元素是否有權(quán)限,在XML配置文件中描述。
例如,下面的JSP頁面有“詳細(xì)”和“修改”兩個(gè)按鈕。
%@ taglib uri="http://mytag" prefix="custTag" %>
html>
head>
title>test/title>
/head>
body >
form name="form1" >
table width="600" border="0" cellspacing="0" cellpadding="2" >
tr>
td>
custTag:JspSecurity elementName="employeedetail" >
input type="button" name="detail" value="詳細(xì)" >
/custTag:JspSecurity>
custTag:JspSecurity elementName="employeemodify" >
input type="button" name="modify" value="修改" >
/custTag:JspSecurity>
/td>
/tr>
/table>
br>
/form>
/body>
下面XML配置文件內(nèi)容表示對(duì)角色為common的用戶,只對(duì)名為employeedetail 的頁面元素即“詳細(xì)”按鈕有權(quán)限,對(duì)角色為“admin”的用戶,對(duì)名為employeedetail 和employeemodify的頁面元素即兩個(gè)按鈕都有權(quán)限。
?xml version="1.0" encoding="GB2312"?>
security>
htmlElement name="employeedetail" >
roleName name="common" />
roleName name="admin" />
/htmlElement>
htmlElement name="employeemodify" >
roleName name="admin" />
/htmlElement>
/security>
定制標(biāo)簽類JspSecurityTag繼承了BodyTagSupport類。BodyTagSupport有一個(gè)變量bodyContent指向起始標(biāo)志和結(jié)束標(biāo)志之間的內(nèi)容。JspSecurityTag的私有靜態(tài)變量roleList保存從XML文件中取到角色和頁面元素的對(duì)應(yīng)集合,私有變量ElementName對(duì)應(yīng)頁面元素的名稱。當(dāng)解析該定制標(biāo)簽時(shí),首先先取到頁面元素的名稱,再取到當(dāng)前用戶的角色,如果角色有該頁面元素的權(quán)限,就顯示標(biāo)簽正文(即頁面元素),否則不顯示。
Pagekage com.presentation.viewhelper.JspSecurityTag;
import javax.servlet.jsp.tagext.*;
import javax.servlet.jsp.*;
import java.util.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;
import org.w3c.dom.*;
import java.io.*;
import javax.xml.parsers.*;
public class JspSecurityTag extends BodyTagSupport {
//保存從XML文件中取到角色和頁面元素的對(duì)應(yīng)集合
private static ArrayList roleList;
//頁面元素的名稱
private String elementName;
public void setElementName(String str)
{
this.elementName=str;
}
public int doAfterBody() throws JspException{
if(roleList==null)
{
roleList=getList();
}
try{
//如果認(rèn)證通過就顯示標(biāo)簽正文,否則跳過標(biāo)簽正文,就這么簡(jiǎn)單
if(isAuthentificated(elementName))
{
if(bodyContent != null){
JspWriter out=bodyContent.getEnclosingWriter();
bodyContent.writeOut(out);
}else
{
}
}
}catch(Exception e){
throw new JspException();
}
return SKIP_BODY;
}
//從XML配置文件中取到角色和頁面元素的對(duì)應(yīng),保存到靜態(tài)的ArrayList
private ArrayList getList()
{
DocumentBuilderFactory dbf =
DocumentBuilderFactory.newInstance();
DocumentBuilder db = null;
Document doc=null;
NodeList childlist = null;
String elementName;
String roleName;
int index;
ArrayList theList = new ArrayList();
try{
db = dbf.newDocumentBuilder();
}catch(Exception e)
{
e.printStackTrace();
}
try{
doc = db.parse(new File("security.xml"));
}catch(Exception e)
{
e.printStackTrace();
}
//讀取頁面元素列表
NodeList elementList = doc.getElementsByTagName("htmlElement");
for(int i=0;ielementList.getLength();i++)
{
Element name = ((Element)elementList.item(i));
//頁面元素的名稱
elementName = name.getAttribute("name");
//該頁面元素對(duì)應(yīng)的有權(quán)限的角色的列表
NodeList rolNodeList = ((NodeList)name.getElementsByTagName("roleName"));
for(int j=0;jrolNodeList.getLength();j++)
{
//有權(quán)限的角色的名稱
//roleName = ((Element)rolNodeList.item(j)).getNodeValue();
roleName = ((Element)rolNodeList.item(j)).getAttribute("name");
theList.add(new ElementAndRole(elementName,roleName));
}
}
return theList;
}
//檢查該角色是否有該頁面元素的權(quán)限
private boolean isAuthentificated(String elementName)
{
String roleName = "";
//在用戶登陸時(shí)把該用戶的角色保存到SESSION中,這里只是直接從SESSION中取用//戶角色。
roleName=this.pageContext.getSession().getAttribute("rolename”);
// roleList包含elementName屬性為elementName,roleName屬性為roleName的//ElementAndRole對(duì)象,則該角色有該頁面元素的權(quán)限
if(roleList.contains(new ElementAndRole(elementName,roleName)))
{
return true;
}
}
return false;
}
//表示角色和頁面元素的對(duì)應(yīng)的關(guān)系的內(nèi)部類
class ElementAndRole{
String elementName;
String roleName;
public ElementAndRole(String elementName,String roleName)
{
this.elementName=elementName;
this.roleName=roleName;
}
public boolean equals(Object obj)
{
return(((ElementAndRole)obj).elementName.equals(this.elementName)((ElementAndRole)obj).roleName.equals(this.roleName));
}
}
}
在標(biāo)簽庫能被JSP頁面使用前,要做以下三個(gè)步驟
1、 在JSP頁面中包括一個(gè)taglib元素,確定需要加載到內(nèi)存的標(biāo)簽庫。前面的JSP文件的第一行:%@ taglib uri="http://mytag" prefix="custTag" %>做的就是這件事。
2、 在配置文件web.xml中使用taglib元素確定TLD文件的位置。在web.xml中增加:
taglib>
taglib-uri>http://mytag/taglib-uri>
taglib-location>
/WEB-INF/mytag.tld
/taglib-location>
/taglib>
3、TLD文件必須使用taglib元素標(biāo)識(shí)每個(gè)定制標(biāo)簽極其屬性。
下面是使用這個(gè)標(biāo)簽庫對(duì)應(yīng)的TLD文件
?xml version="1.0" encoding="ISO-8859-1" ?>
!DOCTYPE taglib
PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
"http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">
taglib>
tlibversion>1.0/tlibversion>
jspversion>1.1/jspversion>
shortname>myTag/shortname>
uri/>
tag>
name>JspSecurity/name>
tagclass>com.presentation.viewhelper.JspSecurityTag/tagclass>
info>
JspSecurityTag
/info>
attribute>
name>elementName/name>
required>true/required>
rtexprvalue>true/rtexprvalue>
/attribute>
/tag>
/taglib>
您可能感興趣的文章:- jsp自定義標(biāo)簽用法實(shí)例詳解
- JSP使用自定義標(biāo)簽防止表單重復(fù)提交的方法
- jsp中自定義標(biāo)簽用法實(shí)例分析
- JSP自定義分頁標(biāo)簽TAG全過程
- jsp自定義標(biāo)簽之ifelse與遍歷自定義標(biāo)簽示例
- JSP自定義標(biāo)簽獲取用戶IP地址的方法
- 基于JSP 自定義標(biāo)簽使用實(shí)例介紹
- JSP自定義標(biāo)簽Taglib實(shí)現(xiàn)過程重點(diǎn)總結(jié)
- jsp 自定義標(biāo)簽實(shí)例
- JSP 自定義標(biāo)簽之一 簡(jiǎn)單實(shí)例
- jsp 標(biāo)準(zhǔn)標(biāo)簽庫簡(jiǎn)析
- jsp通過自定義標(biāo)簽庫實(shí)現(xiàn)數(shù)據(jù)列表顯示的方法