雅加达 EE - 持久身份验证过滤器登录;不传播到 JSP



我一直在研究"还记得我吗?-style 持久认证系统,但在成功验证和登录用户后,我的 JSP 在处理下一页请求或刷新之前不会反映用户已登录。正在写入用于此目的的 cookie,并且正在更新数据库。在 Filter 方法中检查用户对象的登录状态指示用户对象正在正确加载。刷新或导航到其他页面后,该页面显示用户已登录。

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

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

这是为Java EE 5和Struts 1.x站点渲染到JSP而编写的,使用自定义Java EE Filter类作为自动登录的入口点。过滤器首先安装在链中,并映射到我的 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 中的相关代码如下(将 taglib jstl-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 操作处理程序,以及其他疑问。有没有其他方法可以处理这种情况?

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

事实证明,我为持久身份验证设置的过滤器似乎仅在调用 Struts 操作时运行; 因此,它没有在我的网站的索引页面上运行(以及其他页面),但在我的情况下,而是在处理来自索引页的 Struts 操作 AJAX 调用时进行身份验证。我已经为其他非 Struts 页面对此进行了测试,似乎它们都没有通过我实现的过滤器。

我解决这个问题的方法是将代码放入我的登录检查 JSP 中,该 JSP 通过 AJAX 调用 Struts 操作(从而在后台触发过滤器);该操作返回指示用户是否已登录的 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);
            }
        }
    });
}

最新更新