【SSI开发总结.4】Spring中使用Acegi安全框架
<web-app id="WebApp_ID" version="2.4"xmlns="http://java.sun.com/xml/ns/j2ee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/j2eehttp://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>game_proj</display-name>
<!-- 中文语言支持过滤器 -->
<filter>
<filter-name>Set Character Encoding</filter-name>
<filter-class>com.popoann.SetCharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>GBK</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Set Character Encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<!-- Acegi过滤器 -->
<filter-name>acegiFilterChain</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>
<!-- Acegi过滤器URL映射 -->
<filter-mapping>
<filter-name>acegiFilterChain</filter-name>
<url-pattern>*.htm</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>acegiFilterChain</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>acegiFilterChain</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
<!-- ActionContextCleanUp过滤器 -->
<filter>
<filter-name>struts-cleanup</filter-name>
<filter-class>org.apache.struts2.dispatcher.ActionContextCleanUp</filter-class>
</filter>
<filter-mapping>
<filter-name>struts-cleanup</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- SiteMesh的核心过滤器 -->
<filter>
<filter-name>sitemesh</filter-name>
<filter-class>com.opensymphony.module.sitemesh.filter.PageFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>sitemesh</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Struts核心过滤器 -->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
<init-param>
<param-name>struts.action.extension</param-name>
<param-value>htm</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 应用程序启动时,加载SpringIoC容器 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/beans-*.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 欢迎页面 -->
<welcome-file-list>
<welcome-file>index.htm</welcome-file>
</welcome-file-list>
</web-app>
2.配置spring bean
/****** /web-inf/beans-myspace_security.xml ******/
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
"http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<!-- 1.配制认证管理器(AuthenticationManager) -->
<bean id="myspace_authenticationManager"
ref="myspace_userDetailsBo"/>
<property name="passwordEncoder" ref="myspace_passwordEncoder"/>
</bean>
<bean id="myspace_passwordEncoder"
value="myspace_remember_me"/>
</bean>
<!-- 2.配制决策管理器(AccessDecisionManager) -->
<bean id="myspace_accessDecisionManager"
value="false"/>
</bean>
<!-- 3.配制拦截器链(FilterChain) -->
<bean id="myspace_filterChainProxy" value="/j_logout.do"/>
</bean>
<!-- (3) -->
<bean id="myspace_authenticationProcessingFilter"
ref="myspace_authenticationManager"/>
<!-- 登录失败的页面,通常包含出错信息的登录页面 -->
<property name="authenticationFailureUrl" value="/login!error.htm"/>
<!-- 登录后默认跳转页面 -->
<property name="defaultTargetUrl" value="/myspace/hellouser.htm"/>
<!-- 用户登录URL -->
<property name="filterProcessesUrl" value="/j_login.do"/>
<property name="rememberMeServices" ref="myspace_rememberMeServices"/>
</bean>
<!-- (4) cookies验证拦截器-->
<bean id="myspace_rememberMeFilter"
ref="myspace_authenticationManager"/>
<property name="rememberMeServices" ref="myspace_rememberMeServices"/>
</bean>
<bean id="myspace_rememberMeServices"
ref="myspace_userDetailsBo"/>
<property name="parameter" value="myspace_remember_me"/>
<property name="key" value="myspace_remember_me"/>
<property name="tokenValiditySeconds" value="31536000"/>
</bean>
<!-- (5) -->
<bean id="myspace_exceptionFilter"
value="/login.htm"/>
<property name="forceHttps" value="false"/>
</bean>
</property>
<!-- 指定错误页,当前角色不能访问本资源时,定位到错误页 -->
<!-- 出现AccessDeniedException时的handler -->
<property name="accessDeniedHandler">
<bean value="/error.jsp" />
</bean>
</property>
</bean>
<!-- (6) 安全拦截器,整合认证和决策管理器,并定义各种目录结构对应的角色,可用ANT表达式-->
<bean id="myspace_securityInterceptor"
ref="myspace_authenticationManager"/>
<property name="accessDecisionManager" ref="myspace_accessDecisionManager"/>
<property name="objectDefinitionSource">
<value>
PATTERN_TYPE_APACHE_ANT
/myspace/sales_*.htm*=ROLE_SALES_USER
/myspace/provide_*.htm*=ROLE_PROVIDE_USER
</value>
</property>
</bean>
</beans>
一定要注意Filter的配置顺序,还有更多Filter,不过以上足够了
3.编写UserDetails类
/****** myspace_userDetailsBo.java ******/
package bo;
import org.acegisecurity.userdetails.UserDetailsService;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.User;
import org.acegisecurity.userdetails.UsernameNotFoundException;
import org.springframework.dao.DataAccessException;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.GrantedAuthority;
import bo.UserBo;
import java.util.*;
public class UserDetailsBo implements UserDetailsService {
//定义两个角色
private final GrantedAuthority ROLE_SALES_USER=new GrantedAuthorityImpl("ROLE_SALES_USER");
private final GrantedAuthority ROLE_PROVIDE_USER=new GrantedAuthorityImpl("ROLE_PROVIDE_USER");
private UserBo bo;
private model.User user;
private List< model.User> myusers;
private Map<String,String> users=new HashMap<String,String>();;
private GrantedAuthority[] authorities;
//注入业务对象的同时,把得到的用户列表依次拷贝的一个HashMap对象中
public void setBo(UserBo bo) {
this.bo = bo;
myusers=bo.getUserList();
users.put("test", "test");
for(model.User user:myusers){
users.put(user.getUsername().trim(), user.getPassword().trim());
System.out.println(user.getUsername().trim()+"=="+user.getPassword().trim());
}
}
public UserDetailsBo(){
}
/* 必须实现这个接口方法,改方法表示在验证之前,该用户是否存在,如果不存在,当然就没有验证的必要了,如果存在,之前通过表单得到的用户名,密码就要和本类中定义的Hashmap中存在的用户密码名值对做对比,然后根据spring bean配置实现验证 */
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException, DataAccessException {
// TODO Auto-generated method stub
System.out.println(username);
String password=users.get(username);
if(password==null)
throw new UsernameNotFoundException("No such user");
System.out.println(password);
if(bo.getUser(username).getType()==1)
authorities=new GrantedAuthority[]{ROLE_SALES_USER};
else
authorities=new GrantedAuthority[]{ROLE_PROVIDE_USER};
return new User(username,password,true,true,true,true,authorities);
}
}
4. 根据配置,制作登录表单
<table width="167" height="80" border="0" cellpadding="0" cellspacing="0">
<form onSubmit="return doValidate('_login')" id="_login" name="_login" method="post" action="j_login.do">
<tr align="right" type="text" id="j_username" size="15" /></td>
</tr>
<tr type="password" id="j_password" size="15" /></td>
</tr>
<tr align="center"><table width="100%" height="27" border="0" cellpadding="0" cellspacing="0">
<tr>
<td align="center" name="Submit" value="登录" /><input type="checkbox"name="myspace_remember_me"/>
记住用户</td>
</tr>
</table></td>
</tr>
</form>
</table>
注意高亮的三个地方,用户名和密码的字段必须是j_username,j_password,myspace_remember_me这个名称显然要和spring bean配置中,myspace_rememberMeAuthenticationProvider这个bean的key属性对应
到此,安全验证完成。