2

我正在使用 Google Web Toolkit 并使用 spring security 保护服务器。我想在我的业务对象方法中使用 @PreAuthorize - 注释。

这里的问题是,AccessDeniedException(如果用户无权调用此方法则抛出)不是 GWT 可序列化的。所以我需要在每个调用BO方法的RPC服务方法中实现一个额外的try-catch,手动转换异常。我真的很想避免这种额外的尝试捕获!

更多解释:

BO(使用 @PreAuthorize 保护)<< 由 >> GWT RPC 调用,它需要额外的 try-catch 来转换异常。

我发现的只是将特定异常映射到特定页面的映射器,但没有关于如何将异常转换为另一个异常的信息(或提供我自己的实现来抛出我的自定义异常)。

我希望我能以你们能理解的方式描述我的问题。

我找到了这个线程:

http://forum.springsource.org/showthread.php?85937-Method-Security-Throw-custom-exception-instead-of-AccessDeniedException

但是 AccessDecisionManager 只抛出 AccessDeniedException 并且我无法获得一些关于如何根据我的需要自定义它的建议。

提前致谢!

4

3 回答 3

1

我不知道有什么方法可以告诉 Spring Security 使用其他类型而不是 AccessDeniedException。所以我认为你需要在某个地方放置 try/catch 块并更改异常类型。有多个地方可以做到这一点:

  • 您可以覆盖MethodSecurityInterceptor然后配置 Spring Security 以使用您的类。这里可以抛出任何异常类型,所以转换没有问题。但是我认为做conf会更加困难。
  • 如果您使用的解决方案是所有传入的 RPC 调用都通过一个 servlet/控制器(如这里),那么您可以在那里应用转换逻辑。
  • 也许最优雅的解决方案是为每个必要的 bean 应用自定义 AOP 拦截器(可以进行异常包装)。这个拦截器必须实现org.springframework.core.Ordered接口,它可以使用HIGHEST_PRECEDENCE常量来确保它会在之前执行MethodSecurityInterceptor。有关排序的更多详细信息,请参阅此条目(看起来相同的 Ordered 接口用于两种情况:AspectJ 和标准 AOP)。您可以将自@Around("@annotation(org.springframework.security.access.prepost.PreAuthorize)")定义拦截器直接应用于 PreAuthorize 注释,因此无需额外的配置。
于 2013-07-08T14:48:24.043 回答
1

我终于用 MethodInterceptor 做到了(感谢 Maksym Demidas)。我的解决方案如下所示:

我的自定义 MethodInterceptor 将包装所有调用并仅捕获“GWT-non-serializable”AccessDeniedException 以将其转换为标准异常:

public class CustomInterceptor implements MethodInterceptor {

@Override
public Object invoke(MethodInvocation arg0) throws Throwable {

    try {
        System.out.println("********* INTERCEPT: "
                + arg0.getMethod().getName());
        return arg0.proceed();
    } catch (AccessDeniedException e) {
        e.printStackTrace();
        System.out.println("AccessDeniedException for method: "
                + arg0.getMethod().getName());
        throw new Exception("Access denied!");
    }
}

applicationContext.xml 中的重要部分:

    <!-- Define a bean with our custom MethodInterceptor -->
<bean id="debuglnterceptor" class="com.my.server.CustomInterceptor" />

<!-- Register our custom MethodInterceptor to wrap all methods called from 
    com.my.server.services classes -->
<aop:config>
    <aop:advisor advice-ref="debuglnterceptor"
        pointcut="execution(* com.my.server.services..*(..))" />
</aop:config>
于 2013-07-12T09:01:04.240 回答
1

这是使用 Spring AOP开发Maksim Demidas的解决方案:

定义“抛出建议”类型的 Spring AOP 建议。它实现接口 Ordered with HIGHEST_PRECEDENCE 以正确集成其他建议,例如@Secured@PreAuthorize

public class AccessDeniedExceptionInterceptor implements ThrowsAdvice, Ordered {

    public void afterThrowing(AccessDeniedException e) throws GwtAccessDeniedException {

        throw new GwtAccessDeniedException();
    }

    @Override
    public int getOrder() {
        return HIGHEST_PRECEDENCE;
    }
}

在 Spring 上下文文件中,将拦截器定义为 bean:

<bean id="accessDeniedExceptionInterceptor" class="my.interceptor.package.AccessDeniedExceptionInterceptor"/>

在 Spring 上下文文件中,配置安全对象。在此示例中,特定实现的所有公共方法都是安全的:

<!-- Configure global method security for the secured object -->
<security:global-method-security>
    <security:protect-pointcut access="ROLE_USER" 
            expression="execution(public * my.service.package.ServiceImpl.*(..))"/>
</security:global-method-security>

定义服务实现bean:

<bean id="rpcServiceTarget" class="my.service.package.ServiceImpl"/>

为服务定义一个代理,并将其连接到拦截器:

<bean id="rpcService" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="proxyInterfaces" value="my.service.package.Service"/>
    <property name="target" ref="rpcServiceTarget"/>
    <property name="interceptorNames">
        <list>
            <value>accessDeniedExceptionInterceptor</value>
        </list>
    </property>
</bean>

就是这样。如果您使用代理,您将获得从 Spring 的 AccessDeniedException 到您的自定义 GwtAccessDeniedException 的转换。

于 2014-09-03T17:07:31.950 回答