转换Spring Security AccessDeniedException(使用GWT)

转换Spring Security AccessDeniedException(使用GWT),gwt,spring-security,Gwt,Spring Security,我正在使用GoogleWebToolkit,并使用SpringSecurity保护服务器。我想在我的业务对象方法中使用@PreAuthorize-annotation 这里的问题是,GWT不能序列化AccessDeniedException(如果用户无权调用此方法,则会引发该异常)。因此,我需要在每个RPC服务方法中实现一个额外的try-catch,该方法手动调用BO方法转换异常。我真的想避免这种额外的尝试捕捉 还有一些解释: BO(受@PreAuthorize)>GWT RPC保护,需要额外的

我正在使用GoogleWebToolkit,并使用SpringSecurity保护服务器。我想在我的业务对象方法中使用@PreAuthorize-annotation

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

还有一些解释:

BO(受@PreAuthorize)>GWT RPC保护,需要额外的try-catch来转换异常

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

我希望我能用你们能理解的方式来描述我的问题

我发现了这个线索:

但是AccessDecisionManager只抛出AccessDeniedException,我无法得到一些关于如何根据需要定制它的建议


提前谢谢

我不知道如何告诉Spring Security使用其他类型而不是AccessDeniedException。所以我认为您需要将try/catch块放在某个地方,并更改异常类型。有多个地方可以这样做:

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

我终于用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>

以下是使用Spring AOP开发的解决方案:

定义类型为“throws advice”的Spring AOP通知。它实现了以最高优先级排序的接口,以便与其他建议(如
@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>

accessDeniedExceptionInterceptor

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

传入的RPC调用被划分为几个“逻辑模块”,因此我需要实现多个try-catch场景,所有这些场景都将执行相同的操作。但是“售后服务经理”看起来不错。我会试试,稍后再来。谢谢你会来的。也许最优雅的解决方案是为每个必要的bean应用自定义AOP拦截器(可以进行异常包装)。顺便提一下,我不知道如何确保它将在
MethodSecurityInterceptor
之前执行。有一种方法可以定义AOP拦截器的顺序,所以我更新了我的答案。在四处搜索(并阅读这篇:)之后简单地转换或者抛出不同于AccessDeniedException的异常,似乎需要大量的工作和巨大的开销。是否真的有必要由我自己实施所有步骤?我只是想实现一个自定义AfterInvocationProviderManager,捕获AccessDeniedException并抛出一个自定义的。但是在为ProviderManager定义bean时,我需要提供一个提供者列表。我该怎么做才能告诉spring使用默认的呢?从配置文件:''中,会出现错误:''引起原因:java.lang.IllegalArgumentException:需要一个AfterInvocationProviders列表'。当提供一个空列表时,它会出现相同的错误。对于拦截器解决方案+1。很高兴看到它对你有用。关于共享代码的两个要点:1)引入一些自定义ClientAccessDeniedException并使用它可能更方便,而不是使用Eception 2)可能更好的方法是实现
org.springframework.core.Ordered
,并确保您的
CustomInterceptor
始终在
MethodSecurityInterceptor
之后启动