转换Spring Security AccessDeniedException(使用GWT)
我正在使用GoogleWebToolkit,并使用SpringSecurity保护服务器。我想在我的业务对象方法中使用@PreAuthorize-annotation 这里的问题是,GWT不能序列化AccessDeniedException(如果用户无权调用此方法,则会引发该异常)。因此,我需要在每个RPC服务方法中实现一个额外的try-catch,该方法手动调用BO方法转换异常。我真的想避免这种额外的尝试捕捉 还有一些解释: BO(受@PreAuthorize)>GWT RPC保护,需要额外的try-catch来转换异常 我所发现的只是将特定异常映射到特定页面的映射器,但没有关于如何将异常转换为另一个异常的信息(或者提供自己的实现来抛出自定义异常) 我希望我能用你们能理解的方式来描述我的问题 我发现了这个线索: 但是AccessDecisionManager只抛出AccessDeniedException,我无法得到一些关于如何根据需要定制它的建议转换Spring Security AccessDeniedException(使用GWT),gwt,spring-security,Gwt,Spring Security,我正在使用GoogleWebToolkit,并使用SpringSecurity保护服务器。我想在我的业务对象方法中使用@PreAuthorize-annotation 这里的问题是,GWT不能序列化AccessDeniedException(如果用户无权调用此方法,则会引发该异常)。因此,我需要在每个RPC服务方法中实现一个额外的try-catch,该方法手动调用BO方法转换异常。我真的想避免这种额外的尝试捕捉 还有一些解释: BO(受@PreAuthorize)>GWT RPC保护,需要额外的
提前谢谢 我不知道如何告诉Spring Security使用其他类型而不是AccessDeniedException。所以我认为您需要将try/catch块放在某个地方,并更改异常类型。有多个地方可以这样做:
- 您可以覆盖
,然后。在这里,您可以抛出任何异常类型,因此转换没有问题。但是我认为做conf会更加困难MethodSecurityInterceptor
- 若您使用的解决方案是所有传入的RPC调用都通过一个servlet/控制器(如)传递,那个么您可以在那个里应用转换逻辑
- 也许最优雅的解决方案是为每个必要的bean应用自定义AOP拦截器(可以进行异常包装)。此拦截器必须实现
接口,并且它可以使用org.springframework.core.Ordered
常量来确保它将在最高优先级
之前执行。有关排序的更多详细信息,请参阅(两种情况下似乎使用相同的排序接口:AspectJ和标准AOP)。使用方法安全拦截器
您可以将自定义拦截器直接应用于预授权注释,因此无需额外配置@Around(“@annotation(org.springframework.security.access.prepost.PreAuthorize)”)
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
之后启动