安全性是Web应用程序开发工作中最关键的问题之一在基于servlet的应用程序里保护应用程序资源的办法有两种一是对应用程序进行配置(webxml)二是使用Java代码硬编码到程序中前一种方法使用配置文件该方法很灵活这是因为通过使用配置文件无需改写任何代码就可以改变安全策略是一种常见的手段而Struts 是基于servlet技术的所以Struts 的安全策略也可以使用配置文件进行灵活的配置
配置安全策略时有两个概念需要清楚的区分 用户和角色简单的说用户为使用计算机的人可以是个人或组织角色是一个抽象的概念泛指职务或者权限例如张三李四王五三个人有职员主管和经理三个职务(权限)张三是用户张三可以是主管职务代表张三这个用户含有主管的权利
不同的servlet容器所提供的用户和角色管理机制是不相同的我使用的是Tomcat服务器它提供的用户和角色管理机制文件是在其安装目录下的conf目录中的tomcatusersxml文件可以在这个文件里完成对用户和角色的编辑例如
<tomcatusers>
<rolerolename=tomcat/>
<rolerolename=role/>
<userusername=tomcatpassword=tomcatroles=tomcat/>
<userusername=bothpassword=tomcatroles=tomcatrole/>
<userusername=rolepassword=tomcatroles=role/>
</tomcatusers>
这个文件定义了个角色(tomcat和role)和名用户(tomcatboth和role)你可以在tomcatusersxml文件里定义任意多个用户和角色
使用Struts 保护应用程序的资源
Struts 应用程序的安全策略是通过部署webxml文件中的securityconstraint元素实现的该元素的语法定义
<!ELEMENTsecurityconstraint(displayname?webresourcecollection+authconstraint?userdataconstraint?)>
<!ELEMENTdisplayname(#PCDATA)>
<!ELEMENTwebresourcecollection(webresourcenamedescription?urlpattern*httpmethod*)>
<!ELEMENTauthconstraint(description?rolename*)>
<!ELEMENTuserdataconstraint(description?transportguarantee)>
该语法说明了securityconstraint元素可以有一个可选的displayname子元素至少一个webresourcecollection子元素一个可选的authconstraint子元素和一个可选的userdataconstraint子元素
webresourcecollection子元素是用来列出打算保护的Web资源具体的做法是为这些资源设置URL限制它是通过设置webresourcecollection元素包含的子元素实现的
◆ webresourcename是与受保护资源相关联的名称该子元素为必须元素
◆ description对给定资源的描述这个子元素为可选元素
◆ urlpattern用来设置URL表达式与这个URL表达式相匹配的URL地址指向的资源将受到保护该子元素为至少有一个为必须元素
◆ httpmethod用来表明哪些HTTP方法将受到限制例如设置为GET那么所有的GET请求就将受到限制该元素为可选元素
authconstraint元素用于指定可以访问该资源用户角色集合如果没有指定authconstraint元素就将安全约束应用于所有角色它包含下面几个子元素
◆ description描述该元素是可选元素
◆ rolename可以访问保护资源的用户角色该元素可以有多个
◆ userdataconstraint元素用来设置怎样保护在客户端和Web容器之间传递的数据
◆ description 描述可选元素
◆ transportguarantee 该元素有以下几个值
NONE这意味着应用不需要传输保证
INTEGRAL意味着服务器和客户端之间的数据必须以某种方式发送而且在传送中数据不能被篡改
CONFIDENTIAL这意味着传输的数据必须加密
配置完毕securityconstraint元素的基本信息大致为下面的格式
<securityconstraint>
<webresourcecollection>
<webresourcename>AdminArew</webresourcename>
<urlpattern>*action</urlpattern>
</webresourcecollection>
<authconstraint>
<rolename>myeclipseWeb</rolename>
</authconstraint>
</securityconstraint>
这个securityconstraint元素的效果为只要与表达式*action匹配的请求不是来自拥有myeclipseWeb权限的用户Web容器就会阻断它在这里还可以使用httpmethod元素阻断特定方法的请求因为没有使用会阻断所有方法提交的请求
设置完安全策略后还需要设置让用户有机会提供证明证明自己有权限访问这个受限资源的登陆方法允许使用的登陆方法使用loginconfig元素设置下面为loginconfig元素的语法定义
<!ELEMENTloginconfig(authmethod?realmname?formloginconfig?)>
<!ELEMENTauthmethod(#PCDATA)>
<!ELEMENTrealmname(#PCDATA)>
<!ELEMENTformloginconfig(formloginpageformerrorpage)>
loginconfig子元素的描述如下
◆ authmethod指定用来验证用户身份的方法它的值为下面的一个BASICDIGESTFORM或 CLIENTCERT
◆ realmname指定HTTP Basic验证中在标准登陆框中显示的一条提示
◆ formloginconfig元素是在<authmethod>元素值为FORM时使用的它是指定基于表单的登录中应该使用的登录页面和出错页面如果没有使用基于表单的验证则忽略这些元素这个元素的定义如下其中formloginpage用于指定显示登录页面的资源路径 formerrorpage则用于指定用户登录失败时显示出错页面的资源路径
<!ELEMENTformloginconfig(formloginpageformerrorpage)>
<!ELEMENTformloginpage(#PCDATA)>
<!ELEMENTformerrorpage(#PCDATA)>
设置完登陆方法后还应该使用securityrole元素注册允许用来访问受保护资源所有角色在该元素内部使用一个rolename子元素来注册一个角色例如
<securityrole>
<rolename>myeclipseWeb</rolename>
</securityrole>
注册了一个myeclipseWeb的角色
演示示例使用BASIC登陆方法验证用户身份
我使用的Servlet容器是Tomcat找到它的目录下conf目录中的tomcatusersxml文件打开内容如下
<?xmlversion=encoding=utf?>
<tomcatusers>
<rolerolename=myeclipseWeb/>
<rolerolename=myeclipseWebservices/>
<userusername=webservicespassword=webservicespwdroles=myeclipseWebservices/>
<userusername=adminpassword=adminpwdroles=myeclipseWebmyeclipseWebservices/>
<userusername=webpassword=webpwdroles=myeclipseWeb/>
</tomcatusers>
我使用的IDE是myEclipse它配置好Tomcat下的tomcatusersxml文件内容如上我直接使用它了你也可以添加自己的角色和用户该文件定义了个角色和个用户每一个用户都由自己的角色(或者说权限可以有多重权限)
创建Web项目找到webxml配置它使它支持Struts 并且启动Struts 的安全策略
<?xmlversion=encoding=UTF?>
<webappid=WebApp_version=
xmlns=
xmlns:xsi=instance
xsi:schemaLocation=;app__xsd>
<displayname>StrutsBlank</displayname>
<filter>
<filtername>struts</filtername>
<filterclass>orgapachestrutsdispatcherngfilterStrutsPrepareAndExecuteFilter</filterclass>
</filter>
<filtermapping>
<filtername>struts</filtername>
<urlpattern>/*</urlpattern>
</filtermapping>
<welcomefilelist>
<welcomefile>l</welcomefile>
</welcomefilelist>
<!配置应用程序需要保护的资源与什么角色才可以访问它>
<securityconstraint>
<webresourcecollection>
<webresourcename>AdminArew</webresourcename>
<urlpattern>*action</urlpattern>
</webresourcecollection>
<authconstraint>
<rolename>myeclipseWeb</rolename>
</authconstraint>
</securityconstraint>
<!注册可以访问保护资源的角色>
<securityrole>
<rolename>myeclipseWeb</rolename>
</securityrole>
<securityrole>
<rolename>myeclipseWebservices</rolename>
</securityrole>
<!设置登录方法>
<loginconfig>
<authmethod>BASIC</authmethod>
<realmname>UserBasicAuthentication</realmname>
</loginconfig>
</webapp>
创建接收一个字段信息的动作类
publicclassSecureActionextendsActionSupport{
privatestaticfinallongserialVersionUID=L;
privateStringusername;
publicStringgetUsername(){
returnusername;
}
publicvoidsetUsername(Stringusername){
thisusername=username;
}
@Override
publicStringexecute()
{
returnSUCCESS;
}
}
创建strutsxml配置文件声明动作
<?xmlversion=encoding=UTF?>
<!DOCTYPEstrutsPUBLIC
//ApacheSoftwareFoundation//DTDStrutsConfiguration//EN
dtd>
<struts>
<packagename=securePackageextends=strutsdefault>
<actionname=secureclass=strutsactionSecureAction>
<resultname=success>/indexjsp</result>
</action>
</package>
</struts>
创建输入页面inputjsp和结果页面indexjsp
inputjsp:
<body>
<s:formaction=secure>
<s:textfieldname=usernamelabel=Enteryourname></s:textfield>
<s:submitvalue=submit></s:submit>
</s:form>
</body>
indexjsp
<body>
<s:propertyvalue=username/>Welcome
</body>
测试效果在浏览器输入得到如下界面输入Tom点击submit按钮查看效果
看到了登陆框了吧此时我们要访问的资源是一个受限资源所以要求权限验证还记得我们的用户表吧查看用户表输入用户信息查看结果
输入webservices与webservicespwd的用户信息
提示了一个错误这是因为虽然用户信息正确但是webservices用户的没有myeclipseWeb权限
这次输入一个不存在的用户信息
这次获得了一个错误这是登陆失败的提示结果这里会因浏览器的不同而需要不同次数的失败登陆才会得到这个结果
接下来输入一个正确的用户并且拥有webservices权限的用户信息
点击确定获得如下结果
可以看到我们成功的访问了受保护的资源若要传中文字解决方案我已经在前面配置Struts时介绍过了需要修改Struts 默认的编码方式还需要修改页面的编码方式都改为GBK