如何在Spring MVC-Spring Security应用程序中处理GWT RPC调用中的会话过期异常

时间:2012-12-11 14:37:31

标签: spring spring-mvc spring-security gwt-rpc

我有Spring MVC应用程序,其中安全性由Spring Security处理。

UI是使用GWT构建的,GWT使用RPC方法从服务器获取数据。

我需要在会话过期时处理UI的情况: 例如,RPC AsyncCallback可以获取SessionExpiredException类型的异常并弹出窗口,其中包含“您的会话已过期,请单击刷新链接”等消息。

有人处理过这样的问题吗?

感谢。

2 个答案:

答案 0 :(得分:4)

我认为,为了处理传入的GWT调用,您可以使用一些Spring MVC控制器或一些servlet。它可以有以下逻辑

try{
    // decode payload from  GWT call
    com.google.gwt.user.server.rpc.RPC.decodeRequest(...)
    // get spring bean responsible for actual business logic
    Object bean = applicationContext.getBean(beanName);
    // execute business logic and encode response
    return RPC.invokeAndEncodeResponse(bean, ….)
} catch (com.google.gwt.user.server.rpc.UnexpectedException ex) {
    // send unexpected exception to client
    return RPC.encodeResponseForFailure(..., new MyCustomUnexpectedException(), …) ;
}

此案例的解决方案

HttpServletRequest request = getRequest() ; 
if (request.getRequestedSessionId() != null && !request.isRequestedSessionIdValid()) {
    return RPC.encodeResponseForFailure(..., new MyCustomSessionExpiredException(), …) ;
} else {
    // first code snippet goes here
}

然后在客户端代码中捕获自定义会话过期的异常。如果您不直接使用RPC,那么请提供有关GWT和Spring之间的桥实现的更多详细信息。

您还需要强制GWT编译器将MyCustomSessionExpiredException类型包含到序列化白名单中(以防止GWT安全策略停止向客户端传播异常的情况)。解决方案:将MyCustomSessionExpiredException类型包含在每个同步接口的每个方法签名中:

@RemoteServiceRelativePath("productRpcService.rpc")
public interface ProductRpcService extends RemoteService {
    List<Product> getAllProducts() throws ApplicationException;
    void removeProduct(Product product) throws ApplicationException;
}

MyCustomSessionExpiredException extends ApplicationException

然后在客户端代码中显示弹出窗口:

public class ApplicationUncaughtExceptionHandler implements GWT.UncaughtExceptionHandler {
    @Override        
    public void onUncaughtException(Throwable caught) {
        if (caught instanceof MyCustomSessionExpiredException) {
            Window.alert("Session expired");
        }
    }
}

// Inside of EntryPoint.onModuleLoad method
GWT.setUncaughtExceptionHandler(new ApplicationUncaughtExceptionHandler());

答案 1 :(得分:1)

我研究了一下并在此处上传了解决方案http://code.google.com/p/gspring/source/browse/#svn%2Ftrunk%2Fsample%2Fsession-expired%253Fstate%253Dclosed

使用mvn jetty:run-war查看演示后的演示,然后转到rpc-security-sample/index.htm

有两种解决方法

第一个用于传递GWT RemoteServlet的委托代理,该代理在方法调用期间抛出SessionExpiredException。这需要在每个RPC服务方法中声明Exception。示例:http://code.google.com/p/gspring/source/browse/#svn%2Ftrunk%2Fsample%2Fsession-expired%253Fstate%253Dclosed

步骤:

  1. 开发新的过滤器,首先拦截

  2. 在每个RPC方法服务中声明SessionExpiredException,为简单起见,可以继承RuntimeException(无需在实施者中遵循这一点)

  3. 开发父通用AsyncCallback处理程序

  4. 使用http://code.google.com/p/gspring/解决方案来处理所有传入的RCP请求。

  5. 第二个更简单:在UI端返回401 HTTP错误和句柄(GWT本机常规异常包含HTTP状态编号)。示例:http://code.google.com/p/gspring/source/browse/#svn%2Ftrunk%2Fsample%2Fsession-expired-401

    第二种方法最简单,不需要在服务方法契约中声明Exception。但是,遵循第一种方法可以给你一些灵活性:它可以包含一些额外的信息,如上次登录时间(对于SessionExpiredException)等。另外,第二种方法可以引入新的例外,这些例外是从SecurityException继承的,如黑名单用户(例如,如果用户在会话期间被列入黑名单),或者例如,如果用户经常执行相同的操作,例如机器人(可能会要求传递验证码)等。