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