为什么要使用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=?" ; };
|
这里的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>
|
注意<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>
|
好,改了这么多还只是让我们访问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>
|
到这一步,全部的配置都做完了,你可能会有一个疑问:如何在程序中访问到登录的用户名呢?两个方面,在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>
|
在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>
|
仅此而已,是不是很方便?大家可以用上述方法写一个最简单的HelloWorld来试一下。