【问题标题】:Does a GWT app benefit from session clustering?GWT 应用程序是否受益于会话集群?
【发布时间】:2013-05-09 21:53:42
【问题描述】:

许多 Java PaaSes(例如CloudBees session stores)提供会话集群/存储,这样用户在特定请求中被路由到哪个服务器节点并不重要,所有服务器节点共享相同的存储会话数据,因此任何服务都可以为任何客户端请求提供服务。

我想知道这如何应用于客户端 MVC、单页应用程序(如 GWT 应用程序)。

使用 GWT,大多数应用程序都在客户端作为 JavaScript 执行。通常,客户端访问服务器(通过 GWT-RPC 或 RequestFactory)的唯一时间是客户端需要数据时,在这种情况下,它会在后台对GWTServlet 进行特殊调用。

我对共享会话存储的理解是适用于HttpServlet 以及客户端(请求)和服务器(响应)之间的来回对话。但这似乎并不真正适用于 GWT 领域。

所以我问:我的 GWT 应用程序能否从上述应用程序会话存储中受益? 为什么或为什么不?如果是这样,非常非常感谢具体的例子!提前致谢!

示例:

我有一个允许客户端用户执行某些操作的应用:

public class BackOfficeServlet extends HttpServlet {
    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) {
        User u = getUserFromRequest(request);
        Action a = getActionFromRequest(request);

        // If the user is allowed to do the action, then do it.
        if(UserActionAuthenticator.actionIsAllowed(u, a))
            a.execute(u, request);
    }
}

如何/在哪里使用HttpSession 来添加上述代码示例中没有的安全性或功能?

【问题讨论】:

    标签: java session gwt session-state cloudbees


    【解决方案1】:

    仅当您使用会话存储一些数据时,使用会话集群才有意义。问你:你需要在服务器端会话中保存一些东西吗?如果响应为否,则也无需使用会话集群。 GWT 完全是关于有状态的客户端。大多数时候,您可以通过直接在浏览器中保存会话数据来消除对服务器端会话的需要。我给你一个我不想做的例子(在这种情况下会话集群会很有用):

    假设您的应用是一个后台。每个用户都必须登录并且他可以有不同的角色。通常,带有角色的列表将出现在客户端(能够显示/隐藏一些 UI 控件)和服务器端(链接到会话,在服务器端进行两次相同的检查)。您不能信任来自客户端的角色,因为最终用户可能会直接在浏览器中修改它们(即使在缩小 JS 的情况下这是非常复杂的任务)。在这里您有两个选择:1)使用服务器端会话 2)模拟服务器端会话(在每个 RPC 调用中发送一些自定义会话令牌,然后每次重新加载用户角色)。我更喜欢第一个选项,它使我能够重用 Spring Security 等现有安全库(为我节省大量时间/错误)。您可以根据需要选择第二个选项(您的项目有足够的资源来实现和测试您自己的服务器端会话模拟和安全方面的实现,从而使服务器端完全无状态)。

    总结一下:

    1. 您有一些敏感的会话数据 -> 将它们存储在服务器会话中 -> 您需要会话集群
    2. 您的会话数据不敏感/您根本没有它们 -> 将它们存储在浏览器中/没有可存储的东西 -> 您不需要会话和会话集群
    3. 您有一些敏感的会话数据 -> 将它们存储在服务器端的某个位置,并使用一些自定义会话模拟技术为每个请求重新加载它们 -> 您不需要会话集群(但您需要比选项 1 更多的时间来完成它) .

    编辑。 在上面的代码示例中,您可能会遇到以下潜在问题:

    1. 用户以 user1 身份登录(具有 ROLE_USER 权限)。
    2. 他以某种方式生成带有 user2 内部的请求(具有 ROLE_ADMIN 权限)和一些只有在您具有 ROLE_ADMIN 权限时才能执行的操作。
    3. 即使user1没有相应的权限,也会执行这个动作。

    问题的原因是用户对象来自不受信任的来源(请求)并且可以被最终用户修改。我们可以将他存储在服务器端,而不是将他存储在客户端,例如使用服务器端会话:

    public class BackOfficeServlet extends HttpServlet {
        @Override
        public void doPost(HttpServletRequest request, HttpServletResponse response) {
            User u = getUserFromSession(request.getSession(false));
            Action a = getActionFromRequest(request);
    
            if(UserActionAuthenticator.actionIsAllowed(u, a))
                a.execute(u, request);
        }
    }
    

    现在我们可以信任用户对象,因为最终用户无法更改会话对象。

    【讨论】:

    • 感谢@Maksym Demidas (+1) - 我开始了解了,但我认为快速跟进是我困惑的根源:在您上面的示例中,您说您的首选选项是使用服务器端会话来保存“角色列表”以验证用户和操作。但我不明白你为什么不只是在服务器端声明一个名为UserAuthenticator#authenticateUser(Action action, User user) 的bean。这样,在您授予用户 U 执行操作 A 之前,您将使用此 bean 方法检查它是否允许。那么为什么我们需要服务器会话呢?
    • 因为在理论上我可以使用 chrome 检查器,评估一些 JS 代码并将我的 user 对象(例如具有 USER 角色)替换为另一个管理员 user 对象(具有 ADMIN 角色) .我可以用更有趣的东西替换当前的action(例如删除所有产品操作)。然后我可以打电话给你的服务器。在实践中,这将是困难的,但也是可能的。由您来考虑/忽略这种风险。你更清楚了吗?
    • 再次感谢(和+1) - 我认为我们正在取得进展:所以您是说用户可以(困难地)更改客户端请求,从而获得管理员级别的功能。但我仍然不明白集群会话如何阻止这一点。你能解释一下怎么做吗?再次感谢您迄今为止的所有帮助!
    • 因为用户不能直接在服务器端修改敏感数据。所以你需要服务器端会话。如果您希望集群环境中两个请求之间的行为一致,那么您需要集群会话。我的答案已更新。
    • 想象一下你的客户端 JS 触发了两个请求。请求 1 转到原始会话所在的节点 1(用户已通过身份验证,因此没有问题)。请求 2 转到节点 2。如果会话集群关闭,则此处没有会话。用户未通过身份验证 -> AccesDeniedException。确保这种情况在您的环境中是可能的。因为您可以打开“粘性会话”功能(这意味着每个后续请求将始终路由到节点 1)。在这种情况下,只有当您想确保如果节点 1 发生故障,那么用户可以继续工作时,才需要会话集群。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-05
    • 1970-01-01
    • 2011-04-24
    • 1970-01-01
    • 2012-07-09
    • 1970-01-01
    相关资源
    最近更新 更多