如何在Spring MVC Spring Security app中为GWT RPC调用处理会话过期异常

如何在Spring MVC Spring Security app中为GWT RPC调用处理会话过期异常,spring,spring-mvc,spring-security,gwt-rpc,Spring,Spring Mvc,Spring Security,Gwt Rpc,我有一个SpringMVC应用程序,其中安全性由SpringSecurity处理 UI是使用GWT构建的,GWT使用RPC方法从服务器获取数据 我需要在UI上处理会话过期的情况: 例如,RPC AsyncCallback可以获取SessionExpiredException类型的异常,并弹出窗口,显示“您的会话已过期,请单击刷新链接”之类的消息 有人处理过这样的问题吗 谢谢。我想为了处理传入的GWT呼叫,您可以使用一些Spring MVC控制器或servlet。它可以有以下逻辑 try{

我有一个SpringMVC应用程序,其中安全性由SpringSecurity处理

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

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

有人处理过这样的问题吗


谢谢。

我想为了处理传入的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

我做了一些研究,并将解决方案上传到这里

使用
mvn jetty:run war
在签出演示后查看演示,并转到
rpc security sample/index.htm

有两种解决方法

第一个是传递GWT
RemoteServlet
的委托代理,该代理在方法调用期间抛出
SessionExpiredException
。这需要在每个RPC服务方法中声明
异常。例如:

步骤:

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

  • 在每个RPC方法服务中声明
    SessionExpiredException
    ,这些服务可以继承
    RuntimeException
    ,以简化操作(实现者无需遵循此操作)

  • 开发父泛型
    AsyncCallback
    处理程序

  • 使用解决方案处理所有传入的RCP请求

  • 第二个更简单:在UI端返回401HTTP错误和句柄(GWT native general exception包含HTTP状态号)。例如:


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

    非常感谢您分享您的知识。您的方法很好,但它将传输层与业务代理层混合,并使用内部GWT API,这是不受鼓励的。请参阅我的答案中的演示,您可以在谷歌代码托管中找到。谢谢。
    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());