Acegi提出来了几种方案: 1. 如果有一个赞成就同意(具体的说就是只要你在那个URL对应的几个用户组中的一个就让你访问) 2. 如果都赞成就同意(具本的说就是那个URL对应的几个用户组里都有你,你才能访问) 3. 如果都不反对就同意(这个在下面讲投票者的时候再说)
代码 <bean id="accessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased"> <property name="allowIfAllAbstainDecisions"><!-- 是否让全部弃权的通过 --> <value>false</value> </property> <property name="decisionVoters"><!-- 投票者们 --> <ref bean="roleVoter"/> </property> </bean> <script type="text/javascript">render_code();</script> 而投票者呢:Acegi自己实现了一个投票者的类RoleVoter: 现在我用第一种方案,RoleVoter只是在URL对应的用户组里有ROLE_为前缀的才进行投票,否则的话弃权.(我们也可以在配置RoleVoter的时候把ROLE_配置成为别的前缀如JAVA_),分别对URL对应的每个用户组投票,如果用户在这个用户组里就投赞成,不在投反对(在用户组的前缀是ROLE_的前提下)这样就不难体会第三种方案的用途了吧 代码 <bean id="roleVoter" class="org.acegisecurity.vote.RoleVoter"> <property name="rolePrefix"> <value>ROLE_</value><!-- 可以改成别的 --> </property> </bean> <script type="text/javascript">render_code();</script> 这样认证管理器和授权管理器就ok了,别的无论是过滤器还是拦截器都会用到它们两个,因为它们都要验证而这两个就是凭证. 那么那两个访问过滤器呢,先说authenticationProcessingFilter是用于表单登陆的 代码 <bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter"> <property name="authenticationManager"><ref bean="authenticationManager"/></property> <property name="authenticationFailureUrl"><value>/failure.html</value></property><!--登陆失败转向的页面 --> <property name="defaultTargetUrl"><value>/ok.html</value></property><!-- 登陆成功转向的页面 --> <property name="filterProcessesUrl"><value>/check</value></property><!-- 要验证的地址 --> </bean> <script type="text/javascript">render_code();</script> 这样的话加上上面配置的认证管理器就已经可以处理登陆了(注意的是它没有用到授权管理器,因为它只是个访问入口还没有权限的授予) 再说一下HTTP基本认证:它比上面的略复杂一点 需要配置一个 代码 <bean id="BasicProcessingFilterEntryPoint" class="org.acegisecurity.ui.basicauth.BasicProcessingFilterEntryPoint"> <property name="realmName"><value>javafish</value></property><!-- 基本认证对话框上显示的字 --> </bean> 然后 <bean id="BasicProcessingFilter" class="org.acegisecurity.ui.basicauth.BasicProcessingFilter"> <property name="authenticationManager"> <ref bean="authenticationManager"/> </property> <property name="authenticationEntryPoint"> <ref bean="BasicProcessingFilterEntryPoint"/> </property> </bean> <script type="text/javascript">render_code();</script> 即可. 不过在HTTP基本认证里需要注意的地方是:好多人配置好了怎么看不到效果啊,一开始我也是很郁闷,看了BasicProcessingFilter的源代码: String header = httpRequest.getHeader("Authorization");//我们一般进入网页测试的时候这里的header始终是null的 代码 if (logger.isDebugEnabled()) { logger.debug("Authorization header: " + header); } if ((header != null) && header.startsWith("Basic ")) {//从这里可以看到一般的登陆基本认证是不起作用的 ................. <script type="text/javascript">render_code();</script> 只有在服务器上配置哪个目录在访问的时候用HTTP基本认证,它才会起作用(一开始还以为是Acegi的BUG呢) 下面说一下真正对URL资源的保护了filterSecurityInterceptor它的本质是个过滤器,有了前面*管理器的基础了这就很容易了: 代码 <bean id="filterSecurityInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor"> <property name="authenticationManager"> <ref local="authenticationManager"/> </property> <property name="accessDecisionManager"> <ref local="accessDecisionManager"/> </property> <property name="objectDefinitionSource"><!-- 把URL和可访问的用户组对应起来 --> <value> CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON<!-- 把URL全部转化为小写 --> PATTERN_TYPE_APACHE_ANT<!-- 以ANT的形式来配置路径 --> /ok.html=ROLE_USER </value> </property> </bean> <script type="text/javascript">render_code();</script> 光这样配置还是不够的,因为当授权失败的时候会抛出异常的,我们应该配置一个异常过滤器来捕获它,exceptionTranslationFilter它是用来捕获异常的,看一下配置吧: 代码 <bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter"> <property name="authenticationEntryPoint"><ref local="authenticationProcessingFilterEntryPoint"/></property> <property name="accessDeniedHandler"> <bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl"> <property name="errorPage" value="/failure.html"/><!-- 发生异常转向的网页 --> </bean> </property> </bean> <bean id="authenticationProcessingFilterEntryPoint" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint"> <property name="loginFormUrl"><value>/Login.html</value></property><!-- 得到表单的信息 --> <property name="forceHttps"><value>false</value></property><!-- 不用https --> </bean> <script type="text/javascript">render_code();</script> 这样就OK了 最后说一下对类中方法的保护: 首先写一个类并在spring中配置好: 代码 package org.li.acegi; public class TestAcegi { public void Role() { System.out.println("javafish"); } } <bean id="testAcegi" class="org.li.acegi.TestAcegi"/> <script type="text/javascript">render_code();</script> 然看写个servlet访问一下它 代码 package org.li.servlet; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.li.acegi.TestAcegi; import org.springframework.context.ApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; public class TestServlet extends HttpServlet { private static final long serialVersionUID = -5610016980827214773L; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=GBK"); PrintWriter out = response.getWriter(); ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getSession().getServletContext()); TestAcegi test = (TestAcegi)ctx.getBean("testAcegi"); test.Role();//访问TestAcegi类的Role方法 out.println("调用成功"); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request,response); } } <script type="text/javascript">render_code();</script> 准备工作做好了,开始配置Acegi 先在Spring里给Acegi做个代理: 代码 <bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="beanNames"> <list> <value>testAcegi</value><!-- 要代理的Bean的id --> </list> </property> <property name="interceptorNames"> <list> <value>methodSecurityInterceptor</value><!-- 代理为... --> </list> </property> </bean> <script type="text/javascript">render_code();</script> 里面的methodSecurityInterceptor呢配置为: 代码 <bean id="methodSecurityInterceptor" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor"> <property name="authenticationManager"> <ref bean="authenticationManager"/> </property> <property name="accessDecisionManager"> <ref bean="accessDecisionManager"/> </property> <property name="objectDefinitionSource"><!-- 对代理的类的方法开始配置权限 --> <value>org.li.acegi.TestAcegi.Role=ROLE_USER</value> </property> </bean> <script type="text/javascript">render_code();</script> 这样当直接访问http://localhost:8080/AcegiWeb/servlet/TestServlet的时候会发现不可访问,控件台也不输出”javafish”,当输入正确的用户名和密码之后便可以访问. 这样它就对类的方法调用起了保护的作用,这一点可以把Acegi应用到DWR上效果是很理想的. 对于Acegi有很多的过滤器不用全写在web.xml里,acegi提供了一个特殊的过滤器我们可以写成这样,在Web.xml里: 代码 <filter> <filter-name>Acegi</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-name> <url-pattern>/*</url-pattern> </filter-mapping> <context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/applicationContext.xml </param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <listener> <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> </listener> <listener> <listener-class>org.acegisecurity.ui.session.HttpSessionEventPublisher</listener-class> </listener> <servlet> <servlet-name>TestServlet</servlet-name> <servlet-class>org.li.servlet.TestServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>TestServlet</servlet-name> <url-pattern>/servlet/TestServlet</url-pattern> </servlet-mapping> <script type="text/javascript">render_code();</script> 在Spring的配置文件里: 代码 <bean id="chainProxy" class="org.acegisecurity.util.FilterChainProxy"> <property name="filterInvocationDefinitionSource"> <value> CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON PATTERN_TYPE_APACHE_ANT /**=HttpSessionContextIntegrationFilter,authenticationProcessingFilter,BasicProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterSecurityInterceptor </value> </property> </bean> <script type="text/javascript">render_code();</script>