在JBOSS中實現使用者安全認證

banq發表於2002-09-21
為什麼要使用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 class="indent">

這裡的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 class="indent">


注意<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 class="indent">

好,改了這麼多還只是讓我們訪問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 class="indent">

到這一步,全部的配置都做完了,你可能會有一個疑問:如何在程式中訪問到登入的使用者名稱呢?兩個方面,在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 class="indent">

在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 class="indent">

僅此而已,是不是很方便?大家可以用上述方法寫一個最簡單的HelloWorld來試一下。

相關文章