在JBOSS中实现用户安全认证

02-09-21 banq

为什么要使用JBOSS为我们提供的安全体系?

常规的做法是,我们在servlet中取得用户登录信息(用户名和密码),去数据库验证通过后将些信息保存在session中,以便在此用户的整个会话期间能进行相应的权限控制。J2EE架构体系为我们提供了安全、事务和线程等诸多的便利,让我们能专注于业务逻辑的实现。为什么我们在开发J2EE应用时还要采用传统的安全体系呢?

JBossSX框架为我们提供了灵活的安全架构,基本上可以满足我们绝大部分的安全需要(请参考本站《关于用户权限的联想》一文)。

用JBossSX的实现用户认证

我们知道,servlet提供了四种安全认证方式:HTTP Basic Authentication, HTTP Digest Authentication, Form Based Authentication和HTTPS Client Authentication。其中又以表单认证(我们的传统认证方式都是基于表单的)和基本认证应用地最为广泛。下面我就以实例来说明如何在JBoss中实现这两种用户认证。

涉及到用户认证,就先要确定用户的信息如何保存?JBoss为我们提供了多种灵活的LoginModules,比如JaasServerLoginModule,它是在服务器端用两个文本格式的属性文件来记录用户信息的;LdapServerLoginModule用LDAP来保存用户信息。等等。

你肯定要说这样岂不是太不方便了!我如何将用户登录信息与应用中的其它部分联系起来,必竟我们的应用大多基于数据库系统的?不错,上面的方法有其局限性,我们不打算采用。下面我主要谈论的是另一种方式:DatabaseServerLoginModule,顾名思义,这是将用户登录信息保存在数据库中的一种认证模式。

我们要做的步骤如下:

第一步:修改jboss/conf/auth.conf文件,在文件后加上:

example2 { 
org.jboss.security.auth.spi.DatabaseServerLoginModule required 
dsJndiName="java:/mySQLDS" 
principalsQuery="select PASSWORD from sads_userpri where USERID=?" 
rolesQuery="select ROLEID,ROLEGROUP from sads_userpri where USERID=?" 
; 
}; 
<p>

这里的java:/mySQLDS是我在jboss.jcml文件中配置好的数据源(如何配置就不罗嗦了)。后面两句比较重要,principalsQuery是用来查询用户密码的SQL语句,rolesQuery用来查询用户角色和角色组,我把这些信息都存在我的sads_userpri表中,这里你可以修改以适应你现在的应用。

要注意的一点是RoleGroup这个字段必须有,如果你不打算设置角色组,就必需将其值设为字串"Roles"。

各个相关关字段的定义均为varchar(64)即可。

第二步:写一个jboss-web.xml文件,与web.xml文件放在一起,即WEB-INF/下。

<?xml version="1.0" encoding="UTF-8"?> 
<jboss-web> 
<security-domain>java:/jaas/example2</security-domain> 
<ejb-ref> 
<ejb-ref-name>ejb/HelloEJB</ejb-ref-name> 
<jndi-name>Hello</jndi-name> 
</ejb-ref> 
</jboss-web> 
<p>

注意<security-domain> 标签,就是指向我们在auth.conf文件中加上的example2认证方式。下面是EJB的引用标签,把ejb/HelloEJB这个引用名指向Hello这个JNDI名(它在jboss.xml中定义)。

再修改web.xml文件,加上:

<security-constraint> 
<display-name>test</display-name> 
<web-resource-collection> 
<web-resource-name>Collection1</web-resource-name> 
<url-pattern>/*</url-pattern> 
<http-method>GET</http-method> 
<http-method>POST</http-method> 
<http-method>PUT</http-method> 
<http-method>DELETE</http-method> 
<http-method>HEAD</http-method> 
</web-resource-collection> 
<auth-constraint> 
<role-name>Echo</role-name> 
</auth-constraint> 
<user-data-constraint> 
<transport-guarantee>NONE</transport-guarantee> 
</user-data-constraint> 
</security-constraint> 
<login-config> 
<auth-method>BASIC</auth-method> 
<realm-name>sharetop.com</realm-name> 
</login-config> 
<security-role> 
<role-name>Echo</role-name> 
</security-role> 
<ejb-ref> 
<ejb-ref-name>ejb/HelloEJB</ejb-ref-name> 
<ejb-ref-type>Session</ejb-ref-type> 
<home>securityhello.HelloHome</home> 
<remote>securityhello.Hello</remote> 
</ejb-ref> 
</web-app> 
<p>

好,改了这么多还只是让我们访问servlet时会弹出登录窗口,但是如何控制用户权限,我们还没涉及,这方面的知识我就不多说了,任何一本EJB开发的书上都会有涉及。我给出我的例子代码中的ejb-jar.xml文件:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 1.1//EN" "http://java.sun.com/j2ee/dtds/ejb-jar_1_1.dtd"> 
<ejb-jar> 
<enterprise-beans> 
<session> 
<ejb-name>Hello</ejb-name> 
<home>securityhello.HelloHome</home> 
<remote>securityhello.Hello</remote> 
<ejb-class>securityhello.HelloBean</ejb-class> 
<session-type>Stateless</session-type> 
<transaction-type>Container</transaction-type> 
<security-role-ref> 
<description /> 
<role-name>Echo</role-name> 
<role-link>Echo</role-link> 
</security-role-ref> 
</session> 
</enterprise-beans> 
<assembly-descriptor> 
<security-role> 
<description /> 
<role-name>Echo</role-name> 
</security-role> 
<method-permission> 
<role-name>Echo</role-name> 
<method> 
<description /> 
<ejb-name>Hello</ejb-name> 
<method-name>*</method-name> 
</method> 
</method-permission> 
<container-transaction> 
<method> 
<ejb-name>Hello</ejb-name> 
<method-name>*</method-name> 
</method> 
<trans-attribute>Required</trans-attribute> 
</container-transaction> 
</assembly-descriptor> 
</ejb-jar> 
<p>

到这一步,全部的配置都做完了,你可能会有一个疑问:如何在程序中访问到登录的用户名呢?两个方面,在EJB中可以通过Context的getCallerPrincipal()方法取得,在servlet中的request.getUserPrincipal()也可以取得当前用户的Principal对象,关于Principal类,可以参考一下API中的说明。

上面给出的web.xml文件你可能已经看出是基于BASIC认证方式的,如何使用Form认证呢?同样,你可以这样修改:

<login-config> 
<auth-method>FORM</auth-method> 
<form-login-config> 
<form-login-page>/Jsp1.jsp</form-login-page> 
<form-error-page>/Jsp2.jsp</form-error-page> 
</form-login-config> 
</login-config> 
<p>

在Jsp1.jsp文件中我们加入一个表单,注意action和各个元素的命名:

<form method="POST" action="j_security_check"> 
<input type="text" name="j_username"> 
<input type="password" name="j_password"> 
<input type="submit" name="login"> 
</form> 
<p>

仅此而已,是不是很方便?大家可以用上述方法写一个最简单的HelloWorld来试一下。

banq
2002-09-21 17:34

这是转贴