3

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

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

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

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

谢谢。

4

2 回答 2

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());
于 2012-12-12T18:00:52.177 回答
1

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

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

有两种方法可以解决它

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

脚步:

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

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

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

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

第二种更简单:返回 401 HTTP 错误并在 UI 端处理(GWT 原生一般异常包含 HTTP 状态编号)。示例:http ://code.google.com/p/gspring/source/browse/#svn%2Ftrunk%2Fsample%2Fsession-expired-401

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

于 2012-12-16T19:15:48.840 回答