持久化认证过滤登录;不传播到 JSP

Persistent authentication filter logging in; not propagating to JSP

我一直在研究 "Remember Me?" 风格的持久身份验证系统,但是在成功验证并登录用户后,我的 JSPs 直到处理下一个页面请求或刷新。正在写入用于此的 cookie,并且正在更新数据库。在 Filter 方法中检查用户对象的登录状态表明正在正确加载用户对象。刷新或导航到其他页面后,页面显示用户已登录。

为什么第一页没有显示登录成功?

是否有明显的事情我没有在这里做,这会阻止过滤器内对会话数据的更改传播到 JSP?这是一个需要通过强制刷新来克服的限制吗?

这是为 Java EE 5 和 Struts 1.x 网站渲染到 JSP 编写的,使用自定义 Java EE 过滤器 class作为自动登录的入口点。过滤器首先安装在链中,并映射到我的 web.xml.

中的“/*”

我的过滤器方法实现如下所示:

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
    if (!isPersistentAuthEnabled()) {
        chain.doFilter(req, resp);
        return;
    }
    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) resp;
    HttpSession session = request.getSession(false);

    SessionStore store = null;
    if (session != null) {
        store = (SessionStore)session.getAttribute("sessionStore");
    }

    User user = null;
    if (store != null) {
        user = store.getUser();
    }

    if (user == null || user.isLoggedIn()) {
        // Skip authentication if no user object in session, or if already logged in.
        chain.doFilter(req, resp);
        return;
    }

    PersistentAuthenticationManager manager = null;
    try {
        manager = new PersistentAuthenticationManager();
    } catch (Exception e) {
        LOG.warn("skipping");
        chain.doFilter(req, resp);
        return;
    }

    try {
        manager.authenticateUser(user, request, response); // Authenticates based on cookie and DB store
        if (user.isLoggedIn()) {
            LOG.debug("success"); // this is being logged correctly
        }
    } catch (Exception e) {
        LOG.warn("failure");
    }
    chain.doFilter(req, resp);
}

JSP中的相关代码如下(将taglibjstl-core.tld映射到c前缀):

<c:choose>
    <c:when test="${sessionStore.user.loggedIn}">
        <!-- Not shown: Display welcome message -->
    </c:when>
    <c:otherwise>
        <!-- Not shown: Click here to log in -->
    </c:otherwise>
</c:choose>

到目前为止,我已经在 Chrome 和 IE 上对此进行了测试,两者都发生了同样的事情。我的修复想法是通过将用户重定向到同一页面来强制刷新,但我担心这可能会产生一些不良影响,例如如果要针对某些请求点击 Struts 操作处理程序(即. posting things) 在提交重定向之前,还有其他疑问。还有其他方法可以处理这种情况吗?

编辑: 因为我相信我可以安全地假设用户不会在他们第一次访问该网站时提交任何表格或处理微妙的操作,我要走了通过设置登录提示的 JSP 的 AJAX 验证自动刷新。我发现当请求纯 JSP(例如索引页)时,有问题的过滤器不会 运行;它仅在调用 Struts 操作时出现在 运行 中。我很困惑,因为这个特定站点主页上的 AJAX 操作是对用户进行身份验证,而不是 index.jsp 请求;我通过从过滤器中记录请求的 URL 来确定这一点。我会在回答中描述这个过程。

事实证明,当调用 Struts 操作时,我为持久身份验证设置的过滤器似乎仅 运行;因此,它不是 运行ning 在我网站的索引页面上(以及其他页面),但在我的情况下,而是在 AJAX 调用 Struts 操作时进行身份验证 from 索引页已处理。我已经针对其他非 Struts 页面测试了这一点,似乎其中 none 通过了我实施的过滤器。

我解决这个问题的方法是将代码放入我的登录检查 JSP 中,它通过 AJAX 调用 Struts 操作(从而在后台触发过滤器);指示用户是否登录的操作 returns JSON。如果已登录,AJAX 响应处理程序会在短时间内向用户显示重叠通知,然后刷新页面,显示正确的内容,就像用户已登录一样。

JSP 显示登录提示的相关部分(已更新):

<c:choose>
    <c:when test="${sessionStore.user.loggedIn}">
        <!-- Not shown: Display welcome message -->
    </c:when>
    <c:otherwise>
        <script src="/path/to/persistentAuth.js"></script>
        <script type="text/javascript">
            checkPersistentAuthAndRefresh();
        </script>
        <!-- Not shown: Click here to log in -->
    </c:otherwise>
</c:choose>

里面 persistentAuth.js:

function checkPersistentAuthAndRefresh() {
    var refreshPage = function () {
        window.location.reload(true);
    };
    $.ajax({
        url: "http://example.com/path/checkPersistentAuth.do",
        dataType: "json",
        success: function (data) {
            if (data.isLoggedIn) {
                showArbitraryDropDownMessage();
                setTimeout(refreshPage, 100);
            }
        }
    });
}