该篇东西详细的讲述了Acegi的相关配置,并在附件上有测试用的Eclipse工程,内含一个基于内存和一个基于MYSQL数据媒介的安全访问控制。每个配置文件里面都包含详细的注释。
<?xml version="1.0" encoding="UTF-8"?><!-- /** * 基于内存的安全访问控制 * * @date 2008-11-02 * @author brofe@163.com */ --><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <!-- FilterChainProxy, 过滤器链的配置 FilterChainProxy 受FilterToBeanProxy委托组织过滤器链,并按顺序调用,并包含一下配置信息 1、CONVERT_URL_TO_LOWERCASE/UPPERCASE_BEFORE_COMPARISON 表示对URL匹配之前将其转化为小写或大写。 2、PATTERN_TYPE_APACHE_ANT 表示使用Ant的风格匹配URL的描述,默认是使用正则表达式。 3、/**=**,**,** 表示多个过滤器组成的过滤器链,过滤器之间用逗号隔开且直接不能包含回车换行。 4、主要支持的过滤器有:HttpSessionContextIntegrationFilter、ExceptionTranslationFilter、 ChannelProcessingFilter、LogoutFilter、AuthenticationProcessingFilter --> <bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy"> <property name="filterInvocationDefinitionSource"> <value> CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON PATTERN_TYPE_APACHE_ANT /**=authenticationProcessingFilter,logoutFilter,rememberMeProcessingFilter,exceptionTranslationFilter </value> </property> </bean> <!-- AuthenticationProcessingFilter 认证过滤器的配置 Acegi提供多种认证方式,如基于内存、DB、CA、LDAP等。它包含如下配置信息: 1、authenticationManager, 表示指定认证信息的提供者,它负责从储存了用户身份和用户安全信息的媒介中读取认证所需的数据。 2、filterProcessesUrl, 表示处理用户身份认证服务所在的URL。页面表单通过"j_username"、"j_password"传递待认证的用户信息。 3、defaultTargetUrl, 表示认证成功后转向的URL。 4、authenticationFailureUrl, 表示认证失败后转向的URL。 --> <bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter"> <property name="authenticationManager" ref="authenticationManager" /> <property name="authenticationFailureUrl" value="/acegilogin.jsp?login_error=1" /> <property name="defaultTargetUrl" value="/userinfo.jsp" /> <property name="filterProcessesUrl" value="/j_acegi_security_check" /> </bean> <!-- ProviderManager 认证提供者的配置 ProviderManager,从储存了用户身份和用户安全信息的媒介中读取认证所需的数据或者说是一个认证列表。 当一个认证提供者失败Acegi尝试从另外一个认证提供者获取,保证能兼容不同来源的身份认证。如: DaoAuthenticationProvider 从数据库中读取用户信息验证身份 AnonymousAuthenticationProvider 匿名用户身份认证 RememberMeAuthenticationProvider 已存cookie中的用户信息身份认证 AuthByAdapterProvider 使用容器的适配器验证身份 CasAuthenticationProvider 根据Yale中心认证服务验证身份, 用于实现单点登陆 JaasAuthenticationProvider 从JASS登陆配置中获取用户信息验证身份 RemoteAuthenticationProvider 根据远程服务验证用户身份 RunAsImplAuthenticationProvider 对身份已被管理器替换的用户进行验证 X509AuthenticationProvider 从X509认证中获取用户信息验证身份 TestingAuthenticationProvider 单元测试时使用 注意:每个认证者会对自己指定的证明信息进行认证, 如DaoAuthenticationProvider仅对UsernamePasswordAuthenticationToken这个证明信息进行认证。 认证提供者包含以下配置信息: 1、providers,表示可以配置一个或多个认证提供者。 --> <bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager"> <!-- 可以拥有多个认证管理处理类,只要一个认证通过就可以了 --> <property name="providers"> <list> <!-- 基于DAO的认证提供者 --> <ref bean="daoAuthenticationProvider"/> <!-- 基于Cookie的认证提供者 --> <bean class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider"> <property name="key" value="acegicookie" /> </bean> </list> </property> </bean> <!-- DaoAuthenticationProvider 基于DAO的认证提供者的配置 该配置负责从数据库或其他保存用户信息的媒介中获取用户信息进行认证。该类首先从SecurityContextHolder的Authentication 中得到待认证的用户名,并根据该用户名获取保存在数据库或其他媒介中代表真正系统用户的UserDetails对象中。紧接着比较Authentication 和UserDetails的匹配关系(如密码时候相等)。如果两者匹配,认证成功,并将UserDetails的权限信息复制到Authentication中; 如果不匹配,认证失败。 1、userDetailsService, 表示DaoAuthenticationProvider通过UsesDetailsService完成UserDetails的获取工作。 --> <bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider"> <!-- 将用户保存在内存里面的一种简单方式 --> <property name="userDetailsService" ref="userDetailsService" /> </bean> <!-- UserDetailsService, 用户获取UserDetails实例的配置 Acegi根据存储用户信息的媒介不同,提供两个UserDetailsService的实现类: 1、InMemoryDaoImpl:该实现类负责从内存中获取用户信息。它允许通过"userMap"和"userProperties"等媒介中获取用户信息。 2、JdbcDaoImpl:该实现类负责从数据库中获取用户信息。 --> <bean id="userDetailsService" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl"> <!-- 将用户信息和权限信息直接保存在内存中 --> <!-- <property name="userMap"> <value> brofe=123,ROLE_ADMIN lemonade=123,ROLE_USER vistor=123,disabled,ROLE_USER </value> </property> --> <!-- 将用户信息和权限信息保存于Java的属性文件中 --> <property name="userProperties"> <bean class="org.springframework.beans.factory.config.PropertiesFactoryBean"> <property name="location" value="/WEB-INF/users.properties" /> </bean> </property> </bean> <!-- RememberMeProcessingFilter 将Authentication中的用户名和密码保存在客户端Cookie的过滤器 使用Cookie保存用户登陆信息,必须考虑以下安全问题: 1、Cookie是易受攻击的,多用户共享浏览器和垮站点脚本攻击都可能使Cookie失窃。 2、一切可以从Cookie中反推出密码明文的存储方式都是不可接受的。 3、必须将客户端的IP绑定在Cookie中,这样即使Cookie失窃,也不可能在其他的机器上使用。 4、使用Cookie登陆,意味着用户可以不经过显示登陆的方式,获取正常登陆的一切权限。 Acegi Remember-Me中最关键的三个问题: 1、在用户登陆的时候,获取用户名和密码等信息,将其以一定的方式保存到Cookie中。 2、在Cookie的有效期内,当用户访问站点的安全页面时,自动进行登陆。 3、必须提供一个功能,让用户可以手工清除Remember-Me Cookie。 Remeber-Me 中涉及的类和接口: RememberMeServices:该接口是Remember-Me方案中最关键的接口 * void loginSucess(HttpServletRequest req, HttpServletResponse res, Authentication successfulAuthencation) 登陆成功后调用该方法,将用户名和密码保存到Cookie中。 * void loginFail(HttpServletRequest req, HttpServletResponse res)登陆失败后调用该方法 * Authentication autoLogin(HttpServletRequest req, HttpServletResponse res) 从Cookie中自动获取用户名和密码进行自动登陆。 * loginSucess()和loginFail()方法的调用到编制到Acegi的AbstractProcessingFilter抽象过滤器中,这意味着任何 注入了RememberMeServices实例的过滤器都会以适合的方式调用这两个方法。而autoLogin()方法则通过RememberMeProcessingFilter 调用,当RememberMeProcessingFilter发现SecurityContextHolder中不存在有效的Authentication时,autoLogin() 方法自动调用。 Acegi为RememberMeServices接口提供两个实现类: 1、NullRememberMeServices:类似于适配器的实现类,它不做任何有意义的事情,这是AbstractProcessingFilter默认的实现类。 2、TokenBaseRememberMeServices:基于凭证(一般指用户名和密码)的Remember-Me实现类,它真实的实现了接口中的方法。 Acegi通过“_acegi_security_remember_me”的参数值来判断用户是否使用Rememer-Me的功能。 --> <bean id="rememberMeProcessingFilter" class="org.acegisecurity.ui.rememberme.RememberMeProcessingFilter"> <!-- 根据Cookie中的用户信息获得对应的UserDetails,进而重现Authentication --> <property name="authenticationManager" ref="authenticationManager" /> <property name="rememberMeServices" ref="rememberMeServices" /> </bean> <bean id="rememberMeServices" class="org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices"> <!-- Cookie有效时间,单位为秒,默认值是两个星期 --> <property name="tokenValiditySeconds" value="432000" /> <property name="userDetailsService" ref="userDetailsService" /> <!-- 保存在Cookie中的键值 --> <property name="key" value="acegicookie"></property> </bean> <!-- LogoutFilter 退出系统的后置过滤器 因为用户的安全信息通过SecurityContext保存在HttpSession中,故当用户退出系统时必须将其清除;当用户退出系统时常常需要 执行一些相关的操作,如记录用户退出系统的日志,将登陆信息保存到Cookie中的。该过滤器就是为了完成上述任务。 退出系统的过滤器需要知道一下三方面的信息: 1、哪一个URL是退出系统的HTTP请求,通过“filterProcessesUrl”属性指定。默认的为:“/j_acegi_logout”。 2、退出系统前需要执行那些操作及需要执行那些处理器。需要执行的处理器必须实现LogoutHolder接口。Aceig提供两个实现类: * SecuritContextLogoutHolder,该处理器将SecurityContext从HttpSession中删除。 * TokenBaseRememberMeServices,该处理器将Authentication中的用户名和密码保存到客户端的Cookie中。 3、退出系统后转向哪个URL,通过构造函数指定。 --> <bean id="logoutFilter" class="org.acegisecurity.ui.logout.LogoutFilter"> <!-- 指定退出系统后转向的URL --> <constructor-arg value="/acegilogin.jsp" /> <!-- 退出系统前需要执行的处理器 --> <constructor-arg> <list> <!-- 将Remember-Me Cookie中的用户信息清除,我的理解为这样做并不合适 --> <ref bean="rememberMeServices"/> <!-- 该处理器将SecurityContext从HttpSession中删除 --> <bean class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler" /> </list> </constructor-arg> </bean> <!-- ExceptionTranslationFilter 异常转换过滤器 过滤器在过滤器链中的配置必须在FilterSecurityInterceptor之前。过滤器主要拦截登陆异常和越权访问异常。 该过滤器的属性说明: 1、authenticationEntryPoint:表示如果未通过身份认证引发的异常,就将请求导向到该入口。 2、accessDeniedHandler:表示如果用户越权访问,就将请求导向到该入口。 --> <bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter"> <property name="authenticationEntryPoint"> <bean class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint"> <property name="loginFormUrl" value="/acegilogin.jsp" /> <property name="forceHttps" value="false" /> </bean> </property> <property name="accessDeniedHandler"> <bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl"> <property name="errorPage" value="/acegilogin.jsp"></property> </bean> </property> </bean></beans>
相关资源:acegi的详细配置实现