`
likunkun
  • 浏览: 91669 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

浅谈Acegi配置

阅读更多
Acegi配置文档
作者:javafish(likunkun)
Email:javafish@sunxin.org
Acegi是基于Spring的一个开源的安全认证框架,现在的最新版本是1.04。Acegi的特点就是有很多的过滤器:不过我们也用不到这么多的过滤器,只是可以把它们看作为一个个的模块,在用的时候加上自己用的着的即可,由于认证的流程的方面比较复杂导致它的配置很复杂,如果能摸清它的工作原理还是不太难.下面用比较顺着人思维的流程过一遍
这里只列出常用的过滤器和拦载器
1. 过滤器:HttpSessionContextIntegrationFilter,authenticationProcessingFilter,BasicProcessingFilter,RememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter
2. 拦截器:filterSecurityInterceptor(其实它是过滤器,不过把它放在这里更能说明它的功能),methodSecurityInterceptor
看着上面的用红色标出的过滤器是用来认证(表单和HTTP基本认证,当然还有别的不过这两个比较长用)它们是资源访问的入口.其它的过滤器是用来辅助的:HttpSessionContextIntegrationFilter是用来把认证信息记录到Session中的RememberMeProcessingFilter是以cookie的形式来保存认证信息的. anonymousProcessingFilter是在匿名的时候(这时候是没有认证信息的)给这个用户分配一个匿名的认证信息,exceptionTranslationFilter总结一下异常并处理.在实际中选择适合程序的即可.
上面只是资源访问的入口,真正保护资源的是这两个拦截器:filterSecurityInterceptor,拦截URL的类(它是个过滤器)
metohdSecurityInterceptor,拦截类中方法的调用,它们为什么要拦截呢?就是想在访问或调用这些方法之前来判断一下用户是否有访问或调用的权限,有就通过,没有就踢出.
除此之外,Acegi专门做了两个管理器(实际上就是两个类,为什么会用做这两个管理器,因为认证和授权都有一些的操作,这就需要专门做两个管理器了):authenticationManager(class= org.acegisecurity.providers.ProviderManager),授权管理器accessDecisionManager(class=org.acegisecurity.vote.AffirmativeBased)
说白了一个用于认证用户,一个是用于权限的授于的
先来说认证用户,认证管理器有什么东西呢?只内置了一些提供者:这些提供者呢又是什么呢,他们是提供用户的验证身份信息的,比如从数据库或配置文件里读出用户名和密码,在用户的cookie里读出身份信息(rememberMeProcessingFilter用到的[前面讲了的,有印象吧]),或在Session里读出身份验证信息(HttpSessionContextIntegrationFilter起作用的),这里我们只说一下从数据库或配置文件里读出用户名密码来装配验证信息的,其它的配置类似可以找一下对应api在Spring里配置即可,daoAuthenticationProvider是数据库的提供者class=org.acegisecurity.providers.dao.DaoAuthenticationProvider,而它提供的服务呢又有几种,数据库和配置文件(这是Acegi的两个默认的实现)当然也可以自己实现(实现userDetailsService接口就行)
<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
		<property name="providers">
			<list>
				<ref local="daoAuthenticationProvider"/>
			</list>
		</property>
	</bean>
<bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
		<!-- <property name="userDetailsService"><ref local="InMemoryDaoImpl"/></property> --><!-- 这里有两种选择 -->
		<property name="userDetailsService"><ref local="jdbcDaoImpl"/></property>
	</bean>

如果用户名和密码在配置文件里可以用InMemoryDaoImpl,class=org.acegisecurity.userdetails.memory.InMemoryDaoImpl,在这个类的userMap里配置即可:javafish=java,ROLE_USER,配置了一个用户名为javafish,密码为java,用户组为ROLE_USER的用户,不过最常用的还是数据库的JDBC实现(两个二选一)org.acegisecurity.userdetails.jdbc.JdbcDaoImpl里面需要usersByUsernameQuery和authoritiesByUsernameQuery还有数据源dataSource(有人问为什么呢,userByUsernameQuery是用来通过用户名来查密码的,authoritiesByUsernameQuery是用来通过用户名来查权限的,查询数据库肯定的用数据源吧这个里是用的SpringFrameWork的DataSource)它们查询的sql语句是有讲究的,就是查密码的时候查三个第一个是username,第二个是password,第三个是是否可用,查权限的时候查两个:username和authorities(具体看例子)
<bean id="InMemoryDaoImpl" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
		<property name="userMap">
			<value>
				javafish=java,ROLE_USER
			</value>
		</property>
	</bean>
	<bean id="jdbcDaoImpl" class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl">
		<property name="usersByUsernameQuery">
			<value>select username,password,enabled from users where username=?</value>
		</property>
		<property name="authoritiesByUsernameQuery">
			<value>select username,authority from authorities where username=?</value>
		</property>
		<property name="dataSource">
			<ref local="dataSource"/>
		</property>
	</bean>
	
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName">
            <value>com.mysql.jdbc.Driver</value>
        </property>
        <property name="url">
            <value>jdbc:mysql://localhost:3306/test</value>
        </property>
        <property name="username">
            <value>root</value>
        </property>
        <property name="password">
            <value>javafish</value>
        </property>
    </bean>

下面说一下授权,授权管理器又有什么东西呢?accessDecisionManager,Acegi把授权方面弄的比较的形象化,把某个URL或方法是否可以被访问按投票的形式来决定,

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>

而投票者呢: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>

这样认证管理器和授权管理器就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>

这样的话加上上面配置的认证管理器就已经可以处理登陆了(注意的是它没有用到授权管理器,因为它只是个访问入口还没有权限的授予)
再说一下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>

即可.
不过在HTTP基本认证里需要注意的地方是:好多人配置好了怎么看不到效果啊,一开始我也是很郁闷,看了BasicProcessingFilter的源代码:
String header = httpRequest.getHeader("Authorization");//我们一般进入网页测试的时候这里的header始终是null的
if (logger.isDebugEnabled()) {
            logger.debug("Authorization header: " + header);
        }
        if ((header != null) && header.startsWith("Basic ")) {//从这里可以看到一般的登陆基本认证是不起作用的
.................

只有在服务器上配置哪个目录在访问的时候用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>

光这样配置还是不够的,因为当授权失败的时候会抛出异常的,我们应该配置一个异常过滤器来捕获它,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>

这样就OK了
最后说一下对类中方法的保护:
首先写一个类并在spring中配置好:
package org.li.acegi;

public class TestAcegi
{
	public void Role()
	{
		System.out.println("javafish");
	}
}
<bean id="testAcegi" class="org.li.acegi.TestAcegi"/>

然看写个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);
	}

}

准备工作做好了,开始配置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>

里面的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>

这样当直接访问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>

在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>
分享到:
评论
20 楼 ricsson 2007-03-21  
very good!
19 楼 mazzystar 2007-03-21  
我在acegi中用到了remembeme,但是在页面上选择rememberme之后没有任何反映,还得手动登陆。
cookies里的相关信息:ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE
YWRtaW46MTE3NTY3NDk3ODc5NjphYjEzNzk3YzMxYmRkMDg3YjQ2MTY0YjIzOWRlOTlmZQ==
172.10.0.40/acegiPlatform
1536
2108775680
30213545
575214272
29846418
*

不知道还有哪里没配到的,以下是相关的配置:
1.login.jsp中加入了一个单选钮:保存我的信息<input type="checkbox" name="rememberme"/>
2.认证filter
bean id="authenticationProcessingFilter"
		class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
		<property name="authenticationManager"
			ref="authenticationManager" />
		<!-- 登陆失败转向页 -->
		<property name="authenticationFailureUrl"
			value="/jsp/login.jsp?login_error=1" />
		<!-- 登陆成功转向页 -->
		<property name="defaultTargetUrl" value="/jsp/s.jsp" />
		<!-- 对应表单的action请求 -->
		<property name="filterProcessesUrl"
			value="/jsp/j_acegi_security_check" />
		<property name="rememberMeServices" ref="rememberMeServices" />
		<property name="exceptionMappings">
			<value>
				org.acegisecurity.AuthenticationException=/jsp/login.jsp?login_error=user_psw_error
				org.acegisecurity.concurrent.ConcurrentLoginException=/jsp/login.jsp?login_error=too_many_user_error
			</value>
		</property>
	</bean>

3.认证管理器
<bean id="authenticationManager"
		class="org.acegisecurity.providers.ProviderManager">
		<property name="providers"><!-- 可有多个认证提供器,其中一个证通过就可以了 -->
			<list>
				<ref local="rememberMeAuthenticationProvider" />
				<ref local="daoAuthenticationProvider" />
				<ref local="anonymousAuthenticationProvider" />
			</list>
		</property>
		<property name="sessionController">
			<ref bean="concurrentSessionController" />
		</property>

	</bean>

4.
<!--
		当SecurityContextHolder中不存在Authentication.用户授权信息,
		rememberMeProcessingFilter就会调用autoLogin()方法从cookie中获取用户信息,在验证filter之前使用
	-->
	<bean id="rememberMeProcessingFilter"
		class="org.acegisecurity.ui.rememberme.RememberMeProcessingFilter">
		<property name="authenticationManager"
			ref="authenticationManager" />
		<property name="rememberMeServices" ref="rememberMeServices" />
	</bean>

	<!--
		提供rememberMe功能
		
		登陆验证时:登陆成功后会调用loginSuccess方法,在cookie里面保留用户信息,
		格式为:username + ":" + expiryTime + ":" + Md5Hex(username + ":" + expiryTime + ":" + password + ":" + key)
		
		访问页面时:rememberMeProcessingFilter会调用autoLogin方法,在cookie中获取用户信息
	-->
	<bean id="rememberMeServices"
		class="org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices">
		<property name="userDetailsService" ref="jdbcDaoImpl" />
		<property name="authenticationDetailsSource"
			ref="authenticationDetailsSourceHelper" />
		<property name="key" value="springRocks" />
		<property name="parameter" value="rememberme" />
	</bean>

	<bean id="authenticationDetailsSourceHelper"
		class="edu.ccut.acegi.intercept.AuthenticationDetailsSourceHelper" />

	<!--
		验证rememberMe证明信息的合法性,利用两个的key来进行比较验证
	-->
	<bean id="rememberMeAuthenticationProvider"
		class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider">
		<property name="key" value="springRocks" />
	</bean>

	<bean id="sessionRegistry"
		class="org.acegisecurity.concurrent.SessionRegistryImpl" />

	<!--
		退出登陆并且remember-me cookie
	-->
	<bean id="logoutFilter"
		class="org.acegisecurity.ui.logout.LogoutFilter">
		<property name="filterProcessesUrl" value="/jsp/j_acegi_logout" />
		<!-- 退出后指向的 URL -->
		<constructor-arg value="/jsp/index.jsp" />
		<constructor-arg>
			<list>
				<ref bean="rememberMeServices" />
				<bean
					class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler" />
				<ref bean="sessionLogoutHandler" />
			</list>
		</constructor-arg>
	</bean>
	<bean id="sessionLogoutHandler"
		class="edu.ccut.acegi.intercept.SessionLogoutHandler">
		<property name="sessionRegistry">
			<ref bean="sessionRegistry" />
		</property>
	</bean>


在我登陆一次并关闭浏览器时,cookies文件还在,当重新打开浏览器并访问登陆页面时cookies文件被删除。不知道cookies是被什么删除的。
请大家给点建议。
18 楼 ahau205109 2007-03-17  
<br/>
<strong>晨星★~雨泪 写道:</strong><br/>
<div class='quote_div'><br/>
<strong>ahau205109 写道:</strong><br/>
<div class='quote_div'><br/>
<strong>daquan198163 写道:</strong><br/>
<div class='quote_div'>请教几个问题:<br/>
1、密码加密如何处理;<br/>
2、<span><span class='tag'/></span><span><span class='tag'><span>select username,authority from authorities where </span><span class='attribute'>username</span><span>=?取出的</span></span><span><span>authority</span></span><span><span>是什么,应该是role吧;</span></span><span><span class='tag'/><span class='tag'><span/></span><br/>
3、如果像“<span>/<span class='attribute'>ok.html</span><span>=</span><span class='attribute-value'>ROLE_USER</span><span/></span>”这样配置,当系统运行期间,role的增删改如何处理;</span></span></div>
<p><br/>
1.密码加密</p>
<p>  原理解析:</p>
<p><font>(1)<font>authenticationProcessingFilter 中会从你的登陆页面获得用户名和密码</font></font></p>
<p> (2)userDetatilService.<font>loadUserByUsername(String username)需要你根据用户名把用户的信息(</font></p>
<p> 用户名,密码,用户权限)放到你自己的UserDetail; </p>
<p>(3) 调用daoAuthenticationProvider中的passwordEncoder对页面密码进行加密,判断与数据库得到的密钥</p>
<p>     是否相等;</p>
<p><font>&lt;bean class="org.acegisecurity.providers.dao.DaoAuthenticationProvider" id="daoAuthenticationProvider"&gt;&lt;/bean&gt;<br/>
   
&lt;property name="userDetailsService"&gt;<br/>
      &lt;ref local="userDetailsService"&gt;&lt;/ref&gt;<br/>
    &lt;/property&gt;
<br/>
   
&lt;property name="passwordEncoder"&gt;<br/>
      &lt;ref local="passwordEncoder"&gt;&lt;/ref&gt;<br/>
      <!----><br/>
    &lt;/property&gt;
</font></p>
<p> </p>
<p>2.是权限</p>
<p>3.只能自己扩展<font>objectDefinitionSource扩展方式</font></p>
</div>
<p><br/>
本人还是最总关心第三个问题</p>
<p>哪有写好了<font>objectDefinitionSource的扩展??</font></p>
<p>期待中。。。。。。<br/>
<br/>
  且看配置:</p>
<p>   <font>objectDefinitionSource :</font>  <font>FilterInvocationDefinitionSource</font></p>
<p>  <font>FilterInvocationDefinitionSourceEditor类</font></p>
<p>加载权限方法:</p>
<p>权限定义:</p>
<p>s参数值格式如下:</p>
<p><font>CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON<br/>
        PATTERN_TYPE_APACHE_ANT<br/>
        /secure/extreme/**=ROLE_SUPERVISOR<br/>
        /secure/**=IS_AUTHENTICATED_REMEMBERED<br/>
        /**=IS_AUTHENTICATED_ANONYMOUSLY</font></p>
<p><font>public void setAsText(String s) throws IllegalArgumentException {<br/>
        FilterInvocationDefinitionDecorator source = new FilterInvocationDefinitionDecorator();</font></p>
<p><font>        if ((s == null) || "".equals(s)) {<br/>
            // Leave target object empty<br/>
            source.setDecorated(new RegExpBasedFilterInvocationDefinitionMap());<br/>
        } else {<br/>
            // Check if we need to override the default definition map<br/>
            if (s.lastIndexOf(DIRECTIVE_PATTERN_TYPE_APACHE_ANT) != -1) {<br/>
                source.setDecorated(new PathBasedFilterInvocationDefinitionMap());</font></p>
<p><font>                if (logger.isDebugEnabled()) {<br/>
                    logger.debug(("Detected " + DIRECTIVE_PATTERN_TYPE_APACHE_ANT<br/>
                        + " directive; using Apache Ant style path expressions"));<br/>
                }<br/>
            } else {<br/>
                source.setDecorated(new RegExpBasedFilterInvocationDefinitionMap());<br/>
            }</font></p>
<p><font>            if (s.lastIndexOf(DIRECTIVE_CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON) != -1) {<br/>
                if (logger.isDebugEnabled()) {<br/>
                    logger.debug("Detected " + DIRECTIVE_CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON<br/>
                        + " directive; Instructing mapper to convert URLs to lowercase before comparison");<br/>
                }</font></p>
<p><font>                source.setConvertUrlToLowercaseBeforeComparison(true);<br/>
            }</font></p>
<p><font>            BufferedReader br = new BufferedReader(new StringReader(s));<br/>
            int counter = 0;<br/>
            String line;</font></p>
<p><font>            List mappings = new ArrayList();</font></p>
<p><font>            while (true) {<br/>
                counter++;</font></p>
<p><font>                try {<br/>
                    line = br.readLine();<br/>
                } catch (IOException ioe) {<br/>
                    throw new IllegalArgumentException(ioe.getMessage());<br/>
                }</font></p>
<p><font>                if (line == null) {<br/>
                    break;<br/>
                }</font></p>
<p><font>                line = line.trim();</font></p>
<p><font>                if (logger.isDebugEnabled()) {<br/>
                    logger.debug("Line " + counter + ": " + line);<br/>
                }</font></p>
<p><font>                if (line.startsWith("//")) {<br/>
                    continue;<br/>
                }</font></p>
<p><font>                // Attempt to detect malformed lines (as per SEC-204)<br/>
                if (line.lastIndexOf(DIRECTIVE_CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON) != -1) {<br/>
                    // Directive found; check for second directive or name=value<br/>
                    if ((line.lastIndexOf(DIRECTIVE_PATTERN_TYPE_APACHE_ANT) != -1) || (line.lastIndexOf("=") != -1)) {<br/>
                        throw new IllegalArgumentException("Line appears to be malformed: " + line);<br/>
                    }<br/>
                }</font></p>
<p><font>                // Attempt to detect malformed lines (as per SEC-204)<br/>
                if (line.lastIndexOf(DIRECTIVE_PATTERN_TYPE_APACHE_ANT) != -1) {<br/>
                    // Directive found; check for second directive or name=value<br/>
                    if ((line.lastIndexOf(DIRECTIVE_CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON) != -1)<br/>
                        || (line.lastIndexOf("=") != -1)) {<br/>
                        throw new IllegalArgumentException("Line appears to be malformed: " + line);<br/>
                    }<br/>
                }</font></p>
<p><font>                // Skip lines that are not directives<br/>
                if (line.lastIndexOf('=') == -1) {<br/>
                    continue;<br/>
                }</font></p>
<p><font>                if (line.lastIndexOf("==") != -1) {<br/>
                    throw new IllegalArgumentException("Only single equals should be used in line " + line);<br/>
                }</font></p>
<p><font>                // Tokenize the line into its name/value tokens<br/>
                // As per SEC-219, use the LAST equals as the delimiter between LHS and RHS<br/>
                String name = StringSplitUtils.substringBeforeLast(line, "=");<br/>
                String value = StringSplitUtils.substringAfterLast(line, "=");</font></p>
<p><font>                if (!StringUtils.hasText(name) || !StringUtils.hasText(value)) {<br/>
                    throw new IllegalArgumentException("Failed to parse a valid name/value pair from " + line);<br/>
                }</font></p>
<p><font>                // Attempt to detect malformed lines (as per SEC-204)<br/>
                if (source.isConvertUrlToLowercaseBeforeComparison()<br/>
                    &amp;&amp; source.getDecorated() instanceof PathBasedFilterInvocationDefinitionMap) {<br/>
                    // Should all be lowercase; check each character<br/>
                    // We only do this for Ant (regexp have control chars)<br/>
                    for (int i = 0; i &lt; name.length(); i++) {<br/>
                        String character = name.substring(i, i + 1);</font></p>
<p><font>                        if (!character.toLowerCase().equals(character)) {<br/>
                            throw new IllegalArgumentException("You are using the "<br/>
                                + DIRECTIVE_CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON<br/>
                                + " with Ant Paths, yet you have specified an uppercase character in line: " + line<br/>
                                + " (character '" + character + "')");<br/>
                        }<br/>
                    }<br/>
                }</font></p>
<p><font>                FilterInvocationDefinitionSourceMapping mapping = new FilterInvocationDefinitionSourceMapping();<br/>
                mapping.setUrl(name);</font></p>
<p><font>                String[] tokens = org.springframework.util.StringUtils<br/>
                        .commaDelimitedListToStringArray(value);</font></p>
<p><font>                for (int i = 0; i &lt; tokens.length; i++) {<br/>
                    mapping.addConfigAttribute(tokens[i].trim());<br/>
                }</font></p>
<p><font>                mappings.add(mapping);<br/>
            }<br/>
            source.setMappings(mappings);<br/>
        }</font></p>
<p><font>        setValue(source.getDecorated());<br/>
    }</font></p>
<p>   <br/>
=========================================</p>
<p>定义自己的类:</p>
<p><font>package common.spring.acegi.business;</font></p>
<p><font>import java.util.*;</font></p>
<p><font>import org.acegisecurity.*;<br/>
import org.acegisecurity.intercept.*;<br/>
import org.apache.commons.logging.LogFactory;<br/>
import org.apache.commons.logging.Log;<br/>
import org.acegisecurity.intercept.web.FilterInvocationDefinitionDecorator;<br/>
import org.acegisecurity.intercept.web.PathBasedFilterInvocationDefinitionMap;<br/>
import org.acegisecurity.intercept.web.FilterInvocationDefinitionSourceMapping;</font></p>
<p><font>import common.spring.acegi.vo.PreviligeVo;</font></p>
<p><font>public class MObjectDefinitionSource implements ObjectDefinitionSource {<br/>
    private MObjectDefinitionSource() {</font></p>
<p><font>    }</font></p>
<p><font>    private static MObjectDefinitionSource mobjectDefinitionSource;<br/>
    public MObjectDefinitionSource getInstance() {<br/>
        if (mobjectDefinitionSource == null) {<br/>
            mobjectDefinitionSource = new MObjectDefinitionSource();<br/>
        }<br/>
        return mobjectDefinitionSource;<br/>
    }</font></p>
<p><font>    private static final Log logger = LogFactory.getLog(<br/>
            MObjectDefinitionSource.class);<br/>
    private boolean lowercase = true; //采取的匹配模式<br/>
    //Object 是FillterInvocation<br/>
    public ConfigAttributeDefinition getAttributes(Object object) throws<br/>
            IllegalArgumentException {<br/>
        if (!init) {<br/>
            this.initConfigAttributeDefinitions();<br/>
        }<br/>
        return source.getAttributes(object);<br/>
    }</font></p>
<p><font>    public Iterator getConfigAttributeDefinitions() {<br/>
        if (!init) {<br/>
            this.initConfigAttributeDefinitions();<br/>
        }<br/>
        return source.getConfigAttributeDefinitions();<br/>
    }</font></p>
<p><font>    public boolean supports(Class clazz) {<br/>
        return true;<br/>
    }</font></p>
<p><font>    public void setLowercase(boolean lowercase) {<br/>
        this.lowercase = lowercase;<br/>
    }</font></p>
<p><font>    public void setPreviligeType(Integer[] previligeType) {<br/>
        this.previligeType = previligeType;<br/>
    }</font></p>
<p><font>    public boolean isLowercase() {<br/>
        return lowercase;<br/>
    }</font></p>
<p><font>    public Integer[] getPreviligeType() {<br/>
        return previligeType;<br/>
    }</font></p>
<p><font>    //需要加载的权限类型<br/>
    private Integer[] previligeType;<br/>
    private static FilterInvocationDefinitionDecorator source;<br/>
    private static boolean init = false;<br/>
    /*<br/>
     * 功能:重新更新权限列表<br/>
     **/<br/>
    public static void refreshSource() {<br/>
        mobjectDefinitionSource.initConfigAttributeDefinitions();<br/>
    }</font></p>
<p><font>    /*<br/>
     * 加载权限<br/>
     **/<br/>
    private void initConfigAttributeDefinitions() {<br/>
        source = null;<br/>
        //查找系统的权限<br/>
        source = new FilterInvocationDefinitionDecorator();<br/>
        source.setDecorated(new PathBasedFilterInvocationDefinitionMap());<br/>
        source.setConvertUrlToLowercaseBeforeComparison(this.lowercase);<br/>
        List mappings = new ArrayList();<br/>
        PreviligeVo vo[] = PreviligeFactory.loadPrevilige(this.previligeType);<br/>
        if (vo == null) {<br/>
            vo = new PreviligeVo[0];<br/>
        }<br/>
        for (int i = 0; i &lt; vo.length; i++) {<br/>
            FilterInvocationDefinitionSourceMapping mapping = new<br/>
                    FilterInvocationDefinitionSourceMapping();<br/>
            mapping.setUrl(vo[i].getCode()); //其实就是url 如 /login.html<br/>
            mapping.setConfigAttributes(Arrays.asList(vo[i].getRole())); //login.html里的角色<br/>
            mappings.add(mapping);<br/>
        }<br/>
        source.setMappings(mappings);<br/>
        init = true;<br/>
    }</font></p>
<p><font>}<br/>
</font></p>
</div>
<br/>
<br/>
<br/>
<br/>
17 楼 晨星★~雨泪 2007-03-17  
<br/>
<strong>ahau205109 写道:</strong><br/>
<div class='quote_div'><br/>
<strong>daquan198163 写道:</strong><br/>
<div class='quote_div'>请教几个问题:<br/>
1、密码加密如何处理;<br/>
2、<span><span class='tag'/></span><span><span class='tag'><span>select username,authority from authorities where </span><span class='attribute'>username</span><span>=?取出的</span></span><span><span>authority</span></span><span><span>是什么,应该是role吧;</span></span><span><span class='tag'/><span class='tag'><span/></span><br/>
3、如果像“<span>/<span class='attribute'>ok.html</span><span>=</span><span class='attribute-value'>ROLE_USER</span><span/></span>”这样配置,当系统运行期间,role的增删改如何处理;</span></span></div>
<p><br/>
1.密码加密</p>
<p>  原理解析:</p>
<p><font>(1)<font>authenticationProcessingFilter 中会从你的登陆页面获得用户名和密码</font></font></p>
<p> (2)userDetatilService.<font>loadUserByUsername(String username)需要你根据用户名把用户的信息(</font></p>
<p> 用户名,密码,用户权限)放到你自己的UserDetail; </p>
<p>(3) 调用daoAuthenticationProvider中的passwordEncoder对页面密码进行加密,判断与数据库得到的密钥</p>
<p>     是否相等;</p>
<p><font>&lt;bean class="org.acegisecurity.providers.dao.DaoAuthenticationProvider" id="daoAuthenticationProvider"&gt;&lt;/bean&gt;<br/>
   
&lt;property name="userDetailsService"&gt;<br/>
      &lt;ref local="userDetailsService"&gt;&lt;/ref&gt;<br/>
    &lt;/property&gt;
<br/>
   
&lt;property name="passwordEncoder"&gt;<br/>
      &lt;ref local="passwordEncoder"&gt;&lt;/ref&gt;<br/>
      <!----><br/>
    &lt;/property&gt;
</font></p>
<p> </p>
<p>2.是权限</p>
<p>3.只能自己扩展<font>objectDefinitionSource扩展方式</font></p>
</div>
<p><br/>
本人还是最总关心第三个问题</p>
<p>哪有写好了<font>objectDefinitionSource的扩展??</font></p>
<p>期待中。。。。。。<br/>
<br/>
<br/>
</p>
16 楼 ricsson 2007-03-17  
正在学习这东西,感谢楼主!
15 楼 pragmatic 2007-03-17  
认真学习中,感谢楼主!
14 楼 qucai88 2007-03-16  
[b]good article.好东西,呵呵,谢啦
13 楼 ahau205109 2007-03-15  
<br/>
<strong>daquan198163 写道:</strong><br/>
<div class='quote_div'>请教几个问题:<br/>
1、密码加密如何处理;<br/>
2、<span><span class='tag'/></span><span><span class='tag'><span>select username,authority from authorities where </span><span class='attribute'>username</span><span>=?取出的</span></span><span><span>authority</span></span><span><span>是什么,应该是role吧;</span></span><span><span class='tag'/><span class='tag'><span/></span><br/>
3、如果像“<span>/<span class='attribute'>ok.html</span><span>=</span><span class='attribute-value'>ROLE_USER</span><span/></span>”这样配置,当系统运行期间,role的增删改如何处理;</span></span></div>
<p><br/>
1.密码加密</p>
<p>  原理解析:</p>
<p><font>(1)<font>authenticationProcessingFilter 中会从你的登陆页面获得用户名和密码</font></font></p>
<p> (2)userDetatilService.<font>loadUserByUsername(String username)需要你根据用户名把用户的信息(</font></p>
<p> 用户名,密码,用户权限)放到你自己的UserDetail; </p>
<p>(3) 调用daoAuthenticationProvider中的passwordEncoder对页面密码进行加密,判断与数据库得到的密钥</p>
<p>     是否相等;</p>
<p><font>&lt;bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider"&gt;<br/>
    &lt;property name="userDetailsService"&gt;<br/>
      &lt;ref local="userDetailsService"/&gt;<br/>
    &lt;/property&gt;<br/>
    &lt;property name="passwordEncoder"&gt;<br/>
      &lt;ref local="passwordEncoder"/&gt;<br/>
      &lt;!--密码加密算法,客户端输入的密码是明文,但是数据库可能是密钥--&gt;<br/>
    &lt;/property&gt;</font></p>
<p>&lt;/bean&gt;</p>
<p>2.是权限</p>
<p>3.只能自己扩展<font>objectDefinitionSource扩展方式</font></p>
12 楼 huzai 2007-03-14  
您写到:只有在服务器上配置哪个目录在访问的时候用HTTP基本认证,它才会起作用(一开始还以为是Acegi的BUG呢)

怎么配:配置哪个目录在访问的时候用HTTP基本认证呀?

谢谢!
11 楼 zhou_song 2007-03-13  
管理员大哥,这里边的内容能不能不要两边拉动啊。看起来真烦哦。
10 楼 landyou 2007-03-11  
不错,写的很清楚,看了之后总体上更加清楚了
9 楼 zt_smile 2007-01-29  
这是我看到ACEGI中写的最通俗易懂的文章,谢谢楼主。
8 楼 jamesby 2007-01-10  
to daquan198163:

我也想知道你的第3个问题,我想应该从objectDifinitonSource入手吧!
7 楼 daquan198163 2007-01-10  
请教几个问题:<br/>
1、密码加密如何处理;<br/>
2、<span><span class='tag'/></span><span><span class='tag'><span>select username,authority from authorities where </span><span class='attribute'>username</span><span>=?取出的</span></span><span><span>authority</span></span><span><span>是什么,应该是role吧;</span></span><span><span class='tag'/><span class='tag'><span/></span><br/>
3、如果像“<span>/<span class='attribute'>ok.html</span><span>=</span><span class='attribute-value'>ROLE_USER</span><span/></span>”这样配置,当系统运行期间,role的增删改如何处理;</span></span>
6 楼 magice 2007-01-10  
acegi的鉴权做的很好,但是授权方面就很薄弱了,自己做系统如果用acegi的话,那么授权方面还得好好得设计
5 楼 rojazz1999 2007-01-10  
确实是好东西啊 收藏!
4 楼 stamen 2007-01-10  
个人觉得Acegi是Spring最好、最适用的扩展框架了。
3 楼 jamesby 2007-01-09  
正在研究这东西,感谢楼主!
2 楼 andyandyandy 2007-01-09  
好文,授权的地方能讲得再细些就更好了
1 楼 lighter 2007-01-08  
这一排论坛的acegi讨论挺多的,表现最活跃的leondu同学就在做翻译的工作.
这一篇文章挺好的,不要让它沉下去,投一个良好..

相关推荐

    acegi学习整理合集

    "浅谈Acegi配置 - Spring - Java - JavaEye论坛.mht"很可能深入讨论了Acegi的配置细节,包括如何设置安全性过滤器链,配置不同的访问控制策略,以及如何处理异常情况。在Acegi中,配置是非常关键的,因为它定义了...

    acegi资料大全-全集

    `浅谈Acegi配置.mht`系列文件可能探讨了Acegi的配置过程,包括基本的配置元素如`&lt;security:global-method-security&gt;`和`&lt;security:http&gt;`,以及如何定义权限表达式和自定义过滤器。Acegi的配置是其强大之处,但也...

    acegi配置文件

    acegi配置文件清单

    ldap与Acegi? ----Acegi配置文件解剖

    被解剖的acegi配置文件. 博文链接:https://rmn190.iteye.com/blog/175041

    Acegi配置web下载,完整

    Acegi配置.mhtAcegi配置的相关配置的信息在里面有一些

    Acegi配置指南[整理].pdf

    在 Acegi 配置指南中,我们主要关注如何设置和配置 Acegi 框架来保护 Web 应用程序的安全。 首先,我们需要在 `web.xml` 文件中配置 Acegi 的过滤器。在示例代码中,定义了一个名为 `Acegi Filter Chain Proxy` 的...

    Acegi 详细配置说明

    在本文中,我们将深入探讨Acegi的详细配置,并通过实际示例来理解其工作原理。 首先,我们要明白Acegi的核心功能是提供身份验证(Authentication)和授权(Authorization)服务。身份验证是确认用户的身份,而授权...

    acegi

    - "aopacegi"可能是一个包含Acegi与AOP相关配置或实现的文件,可能涉及切面的定义和安全策略的配置。 Acegi Security在过去的开发实践中扮演了重要角色,它的设计理念和实现方式对后来的安全框架产生了深远影响。...

    Acegi配置指南

    在配置Acegi时,首先需要在`web.xml`文件中定义一个名为`Acegi Filter Chain Proxy`的过滤器。这个过滤器是Acegi安全机制的核心,它负责拦截所有请求并根据配置执行相应的安全策略。下面是一段典型的`web.xml`配置...

    acegi实例,acegi详细配置和代码实现

    在本实例中,我们将探讨Acegi Security的配置、详细设置以及如何通过代码实现其功能。 首先,让我们理解Acegi Security的核心概念。该框架提供了一种基于角色的访问控制(RBAC)机制,允许开发人员定义用户权限并...

    Acegi 数据库配置安全策略 源代码及图解

    Acegi 安全框架是Spring生态中的一个早期的安全组件,它提供了一套强大的基于数据库的配置来实现应用程序的安全策略。本资源由王政创作并分享,主要涉及如何将XML配置转换为数据库动态配置,这对于那些需要灵活管理...

    acegi的详细配置实现

    ### Acegi的详细配置实现 #### 一、整体架构概览 **Acegi Security** 是一个为Spring框架设计的安全管理工具,它提供了丰富的安全服务,包括认证(Authentication)、授权(Authorization)以及会话管理(Session ...

    实战Acegi:使用Acegi作为基于Spring框架的WEB应用的安全框架

    Acegi是一个专门为SpringFramework应用提供安全机制的开放源代码项目,全称为Acegi Security System for ...通过这个例子详细介绍如何配置Acegi的各个组件,同时介绍如何扩展Acegi 使其能够从数据库中读取配置信息。

    基于java的ACEGI

    在《实战Acegi:使用Acegi作为基于Spring框架的WEB应用的安全框架.pdf》中,可能会详细讲解如何配置和使用Acegi。以下是一些关键步骤: 1. **添加依赖**:首先,在项目中引入Acegi的依赖库,通常是通过Maven或...

    spring acegi 详细文档

    在Spring Acegi中,安全配置通常通过XML配置文件完成,但也可以使用注解进行简化。配置包括定义访问控制规则、配置认证和授权策略,以及设置安全过滤器链。 例如,以下是一个简单的XML配置示例,定义了一个URL访问...

    Acegi例子代码+一个很好的学习Acegi的网址

    1. **Acegi例子代码**:这个例子代码可能包含了一个简单的Spring应用,演示了如何配置和使用Acegi进行安全控制。通过运行此示例,你可以了解Acegi的配置过程以及如何在实际应用中集成。 2. **学习网址**:提供了一...

    Acegi的简单配置

    jar包 博文链接:https://fengzgxing.iteye.com/blog/248761

Global site tag (gtag.js) - Google Analytics