控制客户端访问是开发一个基于B/S的架构的系统的开发者必须考虑的问题jsp或SERVLET规范的基于配置文件的安全策略对资源的控制是以文件为单位的即只可以定义某个视图全部可以或全部不能被访问一个比较复杂的系统往往要要求对视图的一部分(如JSP页面里的一个按钮)提供访问控制只允许被某种角色的用户访问如果采用可编程的安全策略因为对用户角色和操作的定义在开发时不能定义而且这种策略加大了程序员的工作量它可能不是一种好的办法
我采用定制标签库和和配置文件来解决这个问题把要权限控制的JSP页面元素如BUTTON作为标签的内容为受保护的内容起一个唯一的名称把这个名称作为标签的一个属性某个角色对某个页面元素或一组页面元素是否有权限在xml配置文件中描述
例如下面的JSP页面有“详细”和“修改”两个按钮
<%@ taglib uri="http://mytag" PRefix="custTag" %>
<html>
<head>
<title>test</title>
</head>
<body >
<form name="form" >
<table width="" border="" cellspacing="" cellpadding="" >
<tr>
<td>
<custTag:JspSecurity elementName="employeedetail" >
<input type="button" name="detail" value="详细" >
</custTag:JspSecurity>
<custTag:JspSecurity elementName="employeemodify" >
<input type="button" name="modify" value="修改" >
</custTag:JspSecurity>
</td>
</tr>
</table>
<br>
</form>
</body>
下面XML配置文件内容表示对角色为common的用户只对名为employeedetail 的页面元素即“详细”按钮有权限对角色为“admin”的用户对名为employeedetail 和employeemodify的页面元素即两个按钮都有权限
<?xml version="" encoding="GB"?>
<security>
<htmlElement name="employeedetail" >
<roleName name="common" />
<roleName name="admin" />
</htmlElement>
<htmlElement name="employeemodify" >
<roleName name="admin" />
</htmlElement>
</security>
定制标签类JspSecurityTag继承了BodyTagSupport类BodyTagSupport有一个变量bodyContent指向起始标志和结束标志之间的内容JspSecurityTag的私有静态变量roleList保存从XML文件中取到角色和页面元素的对应集合私有变量ElementName对应页面元素的名称当解析该定制标签时首先先取到页面元素的名称再取到当前用户的角色如果角色有该页面元素的权限就显示标签正文(即页面元素)否则不显示
Pagekage compresentationviewhelperJspSecurityTag;
import javaxservletjsptagext*;
import javaxservletjsp*;
import javautil*;
import orgxmlsax*;
import orgxmlsaxhelpers*;
import orgwcdom*;
import javaio*;
import javaxxmlparsers*;
public class JspSecurityTag extends BodyTagSupport {
//保存从XML文件中取到角色和页面元素的对应集合
private static ArrayList roleList;
//页面元素的名称
private String elementName;
public void setElementName(String str)
{
thiselementName=str;
}
public int doAfterBody() throws JspException{
if(roleList==null)
{
roleList=getList();
}
try{
//如果认证通过就显示标签正文否则跳过标签正文就这么简单
if(isAuthentificated(elementName))
{
if(bodyContent != null){
JspWriter out=bodyContentgetEnclosingWriter();
bodyContentwriteOut(out);
}else
{
}
}
}catch(Exception e){
throw new JspException();
}
return SKip_BODY;
}
//从XML配置文件中取到角色和页面元素的对应保存到静态的ArrayList
private ArrayList getList()
{
DocumentBuilderFactory dbf =
DocumentBuilderFactorynewInstance();
DocumentBuilder db = null;
Document doc=null;
NodeList childlist = null;
String elementName;
String roleName;
int index;
ArrayList theList = new ArrayList();
try{
db = dbfnewDocumentBuilder();
}catch(Exception e)
{
eprintStackTrace();
}
try{
doc = dbparse(new File("securityxml"));
}catch(Exception e)
{
eprintStackTrace();
}
//读取页面元素列表
NodeList elementList = docgetElementsByTagName("htmlElement");
for(int i=;i<elementListgetLength();i++)
{
Element name = ((Element)elementListitem(i));
//页面元素的名称
elementName = namegetAttribute("name");
//该页面元素对应的有权限的角色的列表
NodeList rolNodeList = ((NodeList)namegetElementsByTagName("roleName"));
for(int j=;j<rolNodeListgetLength();j++)
{
//有权限的角色的名称
//roleName = ((Element)rolNodeListitem(j))getNodeValue();
roleName = ((Element)rolNodeListitem(j))getAttribute("name");
theListadd(new ElementAndRole(elementNameroleName));
}
}
return theList;
}
//检查该角色是否有该页面元素的权限
private boolean isAuthentificated(String elementName)
{
String roleName = "";
//在用户登陆时把该用户的角色保存到session中这里只是直接从SESSION中取用//户角色
roleName=thispageContextgetSession()getAttribute("rolename”);
// roleList包含elementName属性为elementNameroleName属性为roleName的//ElementAndRole对象则该角色有该页面元素的权限
if(roleListcontains(new ElementAndRole(elementNameroleName)))
{
return true;
}
}
return false;
}
//表示角色和页面元素的对应的关系的内部类
class ElementAndRole{
String elementName;
String roleName;
public ElementAndRole(String elementNameString roleName)
{
thiselementName=elementName;
thisroleName=roleName;
}
public boolean equals(Object obj)
{
return(((ElementAndRole)obj)elementNameequals(thiselementName)&&((ElementAndRole)obj)roleNameequals(thisroleName));
}
}
}
在标签库能被JSP页面使用前要做以下三个步骤
在JSP页面中包括一个taglib元素确定需要加载到内存的标签库前面的JSP文件的第一行<%@ taglib uri="http://mytag" prefix="custTag" %>做的就是这件事
在配置文件webxml中使用taglib元素确定TLD文件的位置在webxml中增加
<taglib>
<tagliburi>http://mytag</tagliburi>
<tagliblocation>
/WEBINF/mytagtld
</tagliblocation>
</taglib>
TLD文件必须使用taglib元素标识每个定制标签极其属性
下面是使用这个标签库对应的TLD文件
<?xml version="" encoding="ISO" ?>
<!DOCTYPE taglib
PUBLIC "//Sun Microsystems Inc//DTD JSP Tag Library //EN"
"
<taglib>
<tlibversion></tlibversion>
<jspversion></jspversion>
<shortname>myTag</shortname>
<uri/>
<tag>
<name>JspSecurity</name>
<tagclass>compresentationviewhelperJspSecurityTag</tagclass>
<info>
JspSecurityTag
</info>
<attribute>
<name>elementName</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>