THE ROAD AHEAD

ideas for work
随笔 - 3, 文章 - 0, 评论 - 0, 引用 - 0
数据加载中……

(翻译)Spring Security(Part IV)——安全对象的实现

安全对象的实现

23.1. AOP Alliance安全拦截器(MethodInvocation)

Spring Security 2.0之前,对MethodInvocation进行安全管理需要很多恼人的配置。现在推荐的method security的方法是使用命名空间配置。通过这种方式,method security需要的基础设施对象会自动为你配置,你不需要真正知道实现的类。我们在此只提供这些类的一个快速概览。

method security要求使用一个MethodSecurityInterceptor,用来提供MethodInvocation的安全控制。根据配置方式的不同,一个拦截器可以指定给一个对象,或在多个对象间共享。拦截器使用一个MethodDefinitionSource实例来获取应用在特别方法调用上的配置属性。MapBasedMethodDefinitionSource用来保存配置属性,以方法名称为key(可用通配符),当属性是用<intercept-methods><protect-point>元素定义的时候在内部使用。其他实现会在处理annotation-based配置中使用。

23.1.1显式MethodSecurityIterceptor配置

你当然也可以直接配置MethodSecurityIterceptor,和Spring AOP的代理机制一起使用:

<bean id="bankManagerSecurity"
    class="org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor">
 <property name="authenticationManager" ref="authenticationManager"/>
 <property name="accessDecisionManager" ref="accessDecisionManager"/>
 <property name="afterInvocationManager" ref="afterInvocationManager"/>
 <property name="objectDefinitionSource">
    <value>
      org.springframework.security.context.BankManager.delete*=ROLE_SUPERVISOR
      org.springframework.security.context.BankManager.getBalance=ROLE_TELLER,ROLE_SUPERVISOR
    </value>
 </property>
</bean>

23.2. AspectJ安全拦截器 (JoinPoint)

AspectJ安全拦截器跟前面一节中讨论的AOP Alliance安全拦截器很相似。这里我们只讨论不同之处。

AspectJ拦截器叫AspectJSecurityInterceptor。跟AOP Alliance安全拦截器依赖Spring Application Context的配置通过代理来进行织入不同,AspectJSecurityInterceptor是通过AspectJ编译器来进行织入的。在同一个应用中,这两种安全拦截器的用法没有什么大的不同。

让我们先看看AspectJSecurityInterceptor是如何配置到Spring中的:

<bean id="bankManagerSecurity"
        class="org.springframework.security.intercept.method.aspectj.AspectJSecurityInterceptor">
 <property name="authenticationManager" ref="authenticationManager"/>
 <property name="accessDecisionManager" ref="accessDecisionManager"/>
 <property name="afterInvocationManager" ref="afterInvocationManager"/>
 <property name="objectDefinitionSource">
    <value>
        org.springframework.security.context.BankManager.delete*=ROLE_SUPERVISOR
        org.springframework.security.context.BankManager.getBalance=ROLE_TELLER,ROLE_SUPERVISOR
    </value>
</property>
</bean>

正如你所见到的,除了类名,AspectJSecurityInterceptor的配置跟AOP Alliance安全拦截器配置完全一样。实际上这两种拦截器能共用同一个objectDefinitionSource,因为ObjectDefinitionSource是调用java标准的java.lang.reflect.Method而非AOP库特有的类。当然,你的访问决议可以访问AOP库的特定类(例如MethodInvocation JoinPoint),这样当进行访问决议的时候可以考虑添加一系列的标准(例如方法的参数)。

接着你需要定义一个AspectJ方面。例如:

package org.springframework.security.samples.aspectj;
        import org.springframework.security.intercept.method.aspectj.AspectJSecurityInterceptor;
        import org.springframework.security.intercept.method.aspectj.AspectJCallback;
        import org.springframework.beans.factory.InitializingBean;
public aspect DomainObjectInstanceSecurityAspect implements InitializingBean {
private AspectJSecurityInterceptor securityInterceptor;
pointcut domainObjectInstanceExecution(): target(PersistableEntity)
         && execution(public * *(..)) && !within(DomainObjectInstanceSecurityAspect);
Object around(): domainObjectInstanceExecution() {
if (this.securityInterceptor != null) {
 AspectJCallback callback = new AspectJCallback() {
    public Object proceedWithObject() {
    return proceed();
 }
};
return this.securityInterceptor.invoke(thisJoinPoint, callback);
} else {
 return proceed();
}
}
public AspectJSecurityInterceptor getSecurityInterceptor() {
return securityInterceptor;
}
public void setSecurityInterceptor(AspectJSecurityInterceptor securityInterceptor) {
this.securityInterceptor = securityInterceptor;
}
public void afterPropertiesSet() throws Exception {
if (this.securityInterceptor == null)
 throw new IllegalArgumentException("securityInterceptor required");
}
}

在上面的例子中,安全拦截器会被应用到每一个PersistableEntity实例上,这是一个没提到过的抽象类(你可以使用任何你喜欢的其他类或pointcut表达式)。因为proceed();语句仅在around()体内才有特别意义,那种情况需要AspectJCallback。当它想目标对象继续的时候,AspectJSecurityInterceptor调用这个匿名AspectJCallback类。

你需要配置Spring装入AOP Aspect并注入AspectJSecurityInterceptor。下面的bean声明可以做到这个:

<bean id="domainObjectInstanceSecurityAspect"
        class="org.springframework.security.samples.aspectj.DomainObjectInstanceSecurityAspect"
        factory-method="aspectOf">
<property name="securityInterceptor"><ref bean="aspectJSecurityInterceptor"/></property>
</bean>

这样就大功告成了!现在你可以在应用的任何地方创建你的bean了,使用任何你认为合适的方法(如new Person();),他们会应用安全拦截器。

23.3. FilterInvocation安全拦截器

要对FilterInvocation进行安全控制,开发人员要添加一个FilterSecurityInterceptorfilter chain中。下面是一个典型的配置:

application context中,你需要配置如下对象:

<bean id="exceptionTranslationFilter"
        class="org.springframework.security.ui.ExceptionTranslationFilter">
 <property name="authenticationEntryPoint" ref="authenticationEntryPoint"/>
</bean>
<bean id="authenticationEntryPoint"
        class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint">
 <property name="loginFormUrl" value="/acegilogin.jsp"/>
 <property name="forceHttps" value="false"/>
</bean>
<bean id="filterSecurityInterceptor"
        class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
 <property name="authenticationManager" ref="authenticationManager"/>
 <property name="accessDecisionManager" ref="accessDecisionManager"/>
 <property name="objectDefinitionSource">
    <security:filter-invocation-definition-source>
      <security:intercept-url pattern="/secure/super/**" access="ROLE_WE_DONT_HAVE"/>
      <security:intercept-url pattern="/secure/**" access="ROLE_SUPERVISOR,ROLE_TELLER"/>
    </security:filter-invocation-definition-source>
 </property>
</bean>

ExceptionTranslationFilterjava exceptionhttp响应之间提供了一个桥梁。它纯粹关注维护用户界面。该过滤器并不做任何实际的安全操作。如果一个AuthenticationException被检测到,它会调用AuthenticationEntryPoint来开始认证过程(例如,用户登录)。

如果用户请求一项安全控制下的http资源但又还没通过认证,就会调用AuthenticationEntryPoint。这个类处理给用户展示一个适当的界面以便用户可以开始认证过程。Spring Security提供了3个具体的实现:AuthenticationProcessingFilterEntryPoint,用于开始一个form-based认证;BasicProcessingFilterEntryPoint,用于开始一个基于HTTP的认证过程;CasProcessingFilterEntryPoint,用于开始一个JA-SIG Central Authentication Service (CAS)登录。AuthenticationProcessingFilterEntryPointCasProcessingFilterEntryPoint都有可选的属性,可强制使用HTTPS,如果你需要了解这些,请参考JavaDocs

FilterSecurityInterceptor负责处理HTTP资源的安全。与其他安全拦截器一样,它也需要设置AuthenticationManagerAccessDecisionManager,这两个都会在后面的部分进行讨论。FilterSecurityInterceptor也配置了应用到不同的HTTP URL请求的属性。关于配置属性的一个完整讨论在本文档的“概要设计”部分提供。

FilterSecurityInterceptor可以通过两种方式进行配置。第一种方式是上面已经用到的,是使用<filter-invocation-definition-source>命名空间元素。这跟用<filter-chain-map>来配置FilterChainProxy相似,但是<intercept-url>子元素只使用patternaccess属性。第二种方式是通过编写你自己的ObjectDefinitionSource,不过这已经不是本文档讨论的范畴。不论使用何种方式,ObjectDefinitionSource都是负责返回一个ConfigAttributeDefinition对象,其中包含了所有跟该安全HTTP URL相关的配置属性。

应该要注意到FilterSecurityInterceptor.setObjectDefinitionSource()方法实际上需要一个FilterInvocationDefinitionSource实例。这是一个标记接口,他是继承于ObjectDefinitionSource。他只是简单表明这个ObjectDefinitionSource能够理解FilterInvocation。为了保持简单,我们这里继续使用FilterInvocationDefinitionSource作为ObjectDefinitionSource,对大部分FilterSecurityInterceptor的用户来说,他们之间的差异很小。

当使用命名空间方式来配置拦截器的时候,用逗号来分隔每个应用在HTTP URL上的配置属性。每个配置属性都被指定给它自己的SecurityConfig对象。SecurityConfig对象在概要设计部分有进行讨论。ObjectDefinitionSource是由property editor创建的,FilterInvocationDefinitionSource的配置属性与基于对请求URL的表达式评估所得的FilterInvocations的配置属性对应。支持两种标准的表达式语法,缺省是把表达式当作Apache Ant path表达式,为了应付复杂的情况,正则表达式也被支持。path-type属性用来指明使用的pattern表达式类型。不能在同一个定义里混用两种表达式。下面是一个例子,前面的配置中我们使用了Ant path表达式,下面我们用正则表达式来实现:

<bean id="filterInvocationInterceptor"
        class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
 <property name="authenticationManager" ref="authenticationManager"/>
 <property name="accessDecisionManager" ref="accessDecisionManager"/>
 <property name="runAsManager" ref="runAsManager"/>
 <property name="objectDefinitionSource">
    <security:filter-invocation-definition-source path-type="regex">
      <security:intercept-url pattern=""A/secure/super/.*"Z" access="ROLE_WE_DONT_HAVE"/>
      <security:intercept-url pattern=""A/secure/.*"" access="ROLE_SUPERVISOR,ROLE_TELLER"/>
    </security:filter-invocation-definition-source>
 </property>
</bean>

不管采用何种表达式,都是根据它们定义的顺序来进行解析的。因此把其中较为具体的表达式放在前面就比较重要了。这在我们上面的例子中也有反映出来。更加精确的/secure/super/放在了/secure/前面。如果这两个调转过来,/secure/会总是在/secure/super/前面满足了条件,因此永远跑不到/secure/super/

跟其它安全拦截器一起,validateConfigAttributes属性会被读取并检查。如果设为true(缺省),启动应用的时候FilterSecurityInterceptor就会检查提供的配置属性是否有效。它是通过检查每一项配置是否都能被AccessDecisionManagerRunAsManager处理来确定的。如果两个都处理不了,就抛出异常。

posted on 2008-11-03 20:12 ALGO 阅读(942) 评论(0)  编辑  收藏


只有注册用户登录后才能发表评论。


网站导航: