论坛首页 Java企业应用论坛

(翻译)Spring Security-2.0.x参考文档“安全对象实现”

浏览 2481 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-08-12  
安全对象实现
23.1. AOP联盟 (MethodInvocation) 安全拦截器

在Spring Security 2.0之前,安全MethodInvocation需要进行很多厚重的配置。 现在为方法安全推荐的方式,是使用命名空间配置. 使用这个方式,会自动为你配置好方法安全基础bean,,你不需要了解那些实现类。 我们只需要对这些类提供一个在这里提到的快速概述。

方法安全强制使用 MethodSecurityInterceptor,它会保障 MethodInvocation。 依靠配置方法,一个拦截器可能作用于一个单独的bean或者在多个bean之间共享。 拦截器使用MethodDefinitionSource实例获得配置属性,应用特定的方法调用。 MapBasedMethodDefinitionSource通过方法名(也可以是通配符)保存配置属性关键字,当使用<intercept-methods> 或<protect-point>元素把属性定义在application context里,将在内部使用。 其他实现会用来处理基于注解的配置。
23.1.1. 精确的 MethodSecurityIterceptor 配置

你可以使用一个Spring AOP代理机制,直接在你的application context里配置一个 MethodSecurityIterceptor :

<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联盟安全拦截器,就非常简单了。 事实上,我们这节只讨论不同的部分。

AspectJ 拦截器的名字是 AspectJSecurityInterceptor。 与AOP联盟安全拦截器不同,在Spring的application context中的安全拦截器通过代理织入,AspectJSecurityInterceptor是通过AspectJ编译器织入。 在一个系统里使用两种类型的安全拦截器也是常见的,使用AspectJSecurityInterceptor处理领域对象实例的安全,AOP联盟MethodSecurityInterceptor用来处理服务层安全。

让我们首先考虑如何把AspectJSecurityInterceptor配置到spring的application context里:

<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联盟安全拦截器一样。 实际上,两个拦截器共享同样的objectDefinitionSource,ObjectDefinitionSource运行的时候使用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) {
    return proceed();
  }

  AspectJCallback callback = new AspectJCallback() {
      public Object proceedWithObject() {
        return proceed();
      }
  };

  return this.securityInterceptor.invoke(thisJoinPoint, callback);
}

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实例上,这是没提到过的一个抽象类(你可以使用任何其他的类或你喜欢的切点)。 对于那些情况AspectJCallback是必须的,因为proceed();语句只有在around()内部才有意义。 AspectJSecurityInterceptor在想继续执行目标对象时,调用这个匿名AspectJCallback类。

你会需要配置Spring读取切面,织入到AspectJSecurityInterceptor中。 下面的声明会处理这个:

<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,开发者需要添加 FilterSecurityInterceptor 到它们的过滤器链。 典型配置例子如下:

在 application context 你需要配置三个bean:

<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>        

ExceptionTranslationFilter 提供了Java异常和HTTP响应之间的桥梁。 他们与维护的用户接口之间是完全独立的。 过滤器没有执行任何真实的安全处理。 如果一个 AuthenticationException 被检测到,过滤器会调用 AuthenticationEntryPoint 启动认证过程(比如一个用户登录)。

如果用户请求受保护的HTTP请求,但是他们没有认证, AuthenticationEntryPoint 就会被调用。 类处理将对应响应发送给用户,这样验证就可以开始了。 Spring Security提供了三个具体实现:AuthenticationProcessingFilterEntryPoint 对应表单认证, BasicProcessingFilterEntryPoint 对应HTTP基本认证过程,CasProcessingFilterEntryPoint 对应JA-SIG中心认证服务(CAS)登录。 AuthenticationProcessingFilterEntryPoint 和 CasProcessingFilterEntryPoint可以选择强制使用HTTPS,所以如果需要它,请参考JavaDocs。

FilterSecurityInterceptor 用来处理HTTP资源的安全。 像其他安全拦截器一样,它需要引用AuthenticationManager 和 AccessDecisionManager,它们都会在下面的单独章节里进行讨论。 FilterSecurityInterceptor也使用配置属性进行配置,处理不同的HTTP URL请求。 一个对配置属性的完全讨论,提供在这份文档的高级设计章节中。

FilterSecurityInterceptor 可以使用两种方式配置配置属性。 第一种,在上面演示了,使用<filter-invocation-definition-source>命名元素。 它直接使用 <filter-chain-map>配置一个FilterChainProxy,但是<intercept-url>子元素,只使用pattern和access属性。 第二种,写你自己的ObjectDefinitionSource,虽然这个超越了文档的范围。 不论使用哪种方法,ObjectDefinitionSource用来返回ConfigAttributeDefinition对象,包含所有配置属性,分配给单独的受保护HTTP URL。

应该注意 FilterSecurityInterceptor.setObjectDefinitionSource()方法其实期望一个FilterInvocationDefinitionSource实例。 这是一个继承了ObjectDefinitionSource的标记接口。 它直接提供ObjectDefinitionSource,理解FilterInvocation。 基于直接的兴趣,我们继续参考 FilterInvocationDefinitionSource,像一个ObjectDefinitionSource,FilterSecurityInterceptor大多数用户的区别的相关性都很小。

在使用命名空间选项配置拦截器时,逗号用来分隔每个HTTP URL上的不同配置属性。 每个配置属性分配到它自己的SecurityConfig对象里。 SecurityConfig对象在高级设计章中讨论。 被属性编辑器创建的ObjectDefinitionSource,FilterInvocationDefinitionSource,匹配配置属性FilterInvocations,是基于请求URL的表达式计算出来的。 目前支持两种标准表达式语法。 默认的是处理所有表达式,用Apache Ant路径和正则表达式,也支持ore复杂情况。 path-type属性用来指定使用的模式类型。 不能在一个定义里使用组合表达式语法。 比如,上一个配置使用正则表达式,代替Ant路径,会写成下面这样:

<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/则永远不会执行。

像使用其他安全拦截器一样,validateConfigAttributes属性会被检查。 设置成true的时候(默认),在启动的时候 FilterSecurityInterceptor 会检查提供的配置属性是否有效。 它检测每个可以执行的配置属性,通过AccessDecisionManager 或 RunAsManager。 如果没有可以执行的配置属性,会抛出一个异常。
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics