如何阻止用户在XPage中打开新的浏览器会话

时间:2014-12-11 15:22:36

标签: xpages

我有一个前端文档锁定过程,它创建一个Application Scope变量,其中包含UNID / Username / time,然后是一个每30秒更新一次该信息的计时器。如果有人试图打开文档进行编辑,我会检查(使用UNID)以查看是否有其他人拥有该文档。如果时间大于30秒,我取消锁定并允许新用户打开它。

我考虑过与数据库做类似的事情'锁定'这很简单,但我需要一个唯一的浏览器会话标识符。我可以使用ReplicaID / UserName / time构建applicationScope变量,但我还需要一条能识别此浏览器会话的信息。

在某处可以获得这样的信息吗?像浏览器sessionID?

3 个答案:

答案 0 :(得分:3)

您希望每个用户数据库只允许一个打开浏览器窗口/标签。

对于您在浏览器中打开的每个XPage,您必须测试是否已在另一个浏览器窗口/选项卡中打开相同的数据库。如果是这样,请拒绝打开XPage,例如重定向到错误XPage。

仅在服务器端无法执行此操作,因为服务器不知道Xpage在哪个浏览器选项卡中打开。

因此,服务器需要客户的帮助。客户必须向服务器提供唯一浏览器窗口/标签ID

浏览器窗口/标签没有唯一的ID。但是,打开新窗口/标签我们可以创建随机ID 并将其存储在浏览器 sessionStorage 中。这是每个窗口/标签的唯一存储空间。

窗口/选项卡ID 可以通过部分刷新GET发送到服务器,并在应用程序范围变量中存储在服务器上。

此外,服务器必须知道窗口/选项卡何时关闭,以便可以在另一个窗口/选项卡中打开相同的数据库。为此,客户必须告诉服务器"我还活着#34;每隔X秒。

这是完整的解决方案:

创建自定义控件" UniqueBrowserTab"

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
    <xp:eventHandler
        event="onClientLoad"
        submit="false">
        <xp:this.script><![CDATA[
            var secondsIamAliveInterval = 5;
            var tabId = sessionStorage.getItem("tabId");
            if (!tabId) {
                tabId = Math.random();
                sessionStorage.setItem("tabId", tabId);
            }
            function sendTabIdToServer() {
                XSP.partialRefreshGet("#{id:browserTabControl}", {
                    params: {'tabId': tabId}
                });
            }
            sendTabIdToServer();
            setInterval(function() {
                sendTabIdToServer();
            }, secondsIamAliveInterval * 1000);
        ]]></xp:this.script>
    </xp:eventHandler>
    <xp:panel id="browserTabControl">
        <xp:this.rendered><![CDATA[#{javascript:
            var secondsIgnoreOtherSession = 7;
            if (param.tabId) {
                var userName = session.getEffectiveUserName();
                var userData = applicationScope.get(userName);
                var now = new Date().getTime();
                if (userData) {
                    if (userData.tabId !== param.tabId) {
                        if (userData.time + secondsIgnoreOtherSession*1000 > now) {
                            context.redirectToPage("Error.xsp");
                        }
                    }
                } 
                applicationScope.put(userName, {tabId : param.tabId, time: now});
            }
            return true
        }]]></xp:this.rendered>
    </xp:panel>
</xp:view>

包括自定义控件&#34; UniqueBrowserTab&#34;进入每个XPage或例如进入应用程序布局的自定义控件。

<?xml version="1.0" encoding="UTF-8"?>
<xp:view
    xmlns:xp="http://www.ibm.com/xsp/core"
    xmlns:xc="http://www.ibm.com/xsp/custom">
    <xc:UniqueBrowserTab />
    ...
</xp:view>

创建一个XPage Error.xsp,其包含自定义控件&#34; UniqueBrowserTab&#34;。

对于所有浏览器中的用户,每个数据库只允许一个浏览器窗口/选项卡。

答案 1 :(得分:0)

SessionID cookie对于浏览器是唯一的。我相信它是作为部分刷新信息的一部分传递的。

请记住,SessionID对于浏览器的多个窗口都是相同的。我不确定这是不是一个问题。

答案 2 :(得分:0)

感谢所有发布在这里的内容。实际上有两个相似但不同的问题。

在第一个实例中,它是在同一个浏览器中阻止应用程序的多个实例,而Sven的帖子回答了那个实例。

第二个问题是在多个浏览器中打开相同的应用程序。在这种情况下,我将使用一个applicationScope变量appSession,它是一个Map,键为UserName~DBRepID,然后是两个&#39;

客户端计时器事件刷新的时间,该事件更新每个&#34; N&#34;秒。 sessionID = facesContext.getExternalContext()。getRequest()。getSession()。getId();

在之前的页面加载中(可能作为PhaseListener ??)如果sessionID匹配打开页面,我用关键UserName~RepID查找appSession。如果appSession中的时间到期,则将时间设置为当前时间,并将sessionID设置为当前的getID()并打开页面。如果没有,则打开错误页面。 sessionID必须有一个计时器,这样如果用户关闭浏览器或选项卡,它最终会超时。我使用类似这样的东西来制作XPage文档锁定例程并且效果很好。

我还没有将这些全部放在一起,但它看起来好像应该完成工作。如果有人看到更好的方法,我会很高兴听到。