Spring的Acegi security的配置,和JDK1.5的一些問題
新的項目沒有開始于是抽空做一個通用一些的Security,后來又考慮到CAS和SSL的認證問題俺還沒有弄懂,就選擇直接使用Spring的子項目acegi
acegi是基于Spring的的一個安全框架,支持HTTP基本(basic)驗證、HTTP Request Session驗證、安全通道、ACL等等,功能強大。配置比較簡單,但是還是要寫一下:
1. 下載Spring Acegi的jar文件和它的源代碼,在它的binary包中有一個contacts.war,這個是acegi的示例,把它放在tomcat的webapps下直接運行即可,這個是acegi很好的參考。
2. 將acegi的Http Servlet Filter配置在web.xml中。
<!-- Acegi Security-->
<filter>
<filter-name>Acegi Filter Chain Proxy</filter-name>
<filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class>
<init-param>
<param-name>targetClass</param-name>
<param-value>org.acegisecurity.util.FilterChainProxy</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Acegi Filter Chain Proxy</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3. 將contract示例下的applicationContext-acegi-security.xml放在ClassPath下或WEB-INF下,并且在web.xml中指出該文件的位置:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath*:/net/chinasam/common/applicationContext-*.xml
/WEB-INF/ applicationContext-acegi-security.xml</param-value>
</context-param>
4. 在applicationContext-acegi-security.xml中找到下面的bean定義
<bean id="jdbcDaoImpl" class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl">
<property name="dataSource">
<ref bean="dataSource" />
</property>
</bean>
可以看到dataSource屬性必須引用一個DataSource,修改這個bean,是之使用一個Spring管理的DataSource實例。JdbcDaoImpl是查詢數據庫的實現類,這個類使用下面的SQL進行查詢:
"SELECT username,password,enabled FROM users WHERE username = ?";
"SELECT username,authority FROM authorities WHERE username = ?";
前者查詢用戶,后者查詢角色,你可以根據實際項目的情況進行修改:設置JdbcDaoImpl的authoritiesByUsernameQuery和usersByUsernameQuery屬性。這個我沒有設置過,因為我的數據庫結構和這個一樣。Acegi沒有包含用戶管理,關于User的CRUD你必須自己完成,然后通過這兩個屬性告訴acegi如何查詢用戶和角色。
5. 密碼編碼,經常需要給密碼進行編碼,常用的算法包括MD5,SHA等,applectionContext –acegi-Security.xml中的配置為:
<bean id="passwordEncoder" class="org.acegisecurity.providers.encoding.Md5PasswordEncoder" />
注意,如果使用上述配置,數據庫中的password字段內容必須是實際內容的MD5摘要。
6. ApplicationContext-acegi-securtiy.xml缺省的使用HTTP Request驗證,也就是通過普通的HTML標單提交用戶名和口令,所以你必須編寫自己的login頁面,以下是一個例子,注意黑體字部分:
<form name="login_form"action="<c:urlvalue='j_acegi_security_check'/>"method="POST">
<table width="241" border="0" cellpadding="0" cellspacing="0" align="center">
<tr>
<td><img src="<fmt:messagekey="login.title.img"/>"width="241" height="26"></td>
</tr>
<tr>
<td>
<table width="241" align="center" cellpadding="0" cellspacing="0">
<tr>
<td width="1" bgcolor="#D2DBE8"></td>
<td align="left"> <fmt:message key="username"/></td>
<td align="left">
<input type="text" class="text" name="j_username"></td>
<td rowspan="4">
<img src="<fmt:messagekey="login.button.img"/>"onclick="javascript:login_form.submit()" style="cursor:hand">
</td>
<td width="1" bgcolor="#D2DBE8"></td>
</tr>
<tr>
<td width="1" bgcolor="#D2DBE8"></td>
<td align="left"> <fmt:message key="password"/></td>
<td align="left"><input type="password" class="text" name="j_password"></td>
<td width="1" bgcolor="#D2DBE8"></td>
<tr>
<td width="1" bgcolor="#D2DBE8"></td>
<td align="left" colspan="3"> <fmt:message key="rememberme"/>
<input type="checkbox" name="_acegi_security_remember_me"></td>
<td width="1" bgcolor="#D2DBE8"></td>
</tr>
</table>
</td></tr>
<c:if test="${! empty param.login_error}">
<tr><td><br>
<fmt:message key="login.failed"/>
<%= ((AuthenticationException) session.getAttribute(AbstractProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY)).getMessage() %>
</td> </tr> </c:if> </table> </form>
最后,你需要配置URL權限,關于POJO的方法權限俺還沒有弄懂,而且,如果不提供遠程訪問的情況下,一般來說也不需要。在ApplicationContext-acegi-securtiy.xml找到bean:filterInvocationInterceptor 這個是基于Http Request驗證的權限terceptor,注意設置bjectDefinitionSource屬性,下面是例子,URL的格式是參考ANT的格式,也可以根據正則表達式的寫法:
<property name="objectDefinitionSource">
<value>
<![CDATA[
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/index.faces=ROLE_SUPERVISOR,ROLE_ANONYMOUS,ROLE_USER
/login.jsp*=ROLE_SUPERVISOR,ROLE_ANONYMOUS,ROLE_USER
/images/*.*=ROLE_SUPERVISOR,ROLE_ANONYMOUS,ROLE_USER
/common/*.*=ROLE_SUPERVISOR,ROLE_ANONYMOUS,ROLE_USER
/styles/*.*=ROLE_SUPERVISOR,ROLE_ANONYMOUS,ROLE_USER
/**=ROLE_USER
]]>
</value>
各個權限入口的順序十分重要,注意必須把特殊的URL權限寫在一般的URL權限之前。
7. Acegi 1.0是基于JDK1.5的,雖然你可以在1.4下使用,但是我還是把我的項目改為JDK1.5,沒成想還出現了一些問題。另外JSTL的也不同了,如果你想使用EL,則必須這樣引用core:
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %>
在JDK1.4下使用String.replaceFirst和replaceAll方法沒有問題,但是在JDK1.5下卻報IllegalArgumentException,getMessage指出Illegal group arguments,但是單獨寫測試類運行卻沒有任何問題,我只好些了自己的replace算法,可是總覺得應該使用JDK提供的,希望達人指教。
8.關于如何使用ACL、SSL等驗證,俺需要進一步研究。
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1488354