如果JSF页面受j_security_check保护,则不会在ajax请求上抛出ViewExpiredException - 跟进

时间:2012-12-18 17:02:42

标签: ajax jsf-2 j-security-check viewexpiredexception

当登录页面是JSF页面时,

ViewExpiredException not thrown on ajax request if JSF page is protected by j_security_check提供解决方案。但是如果登录页面是JSP页面怎么办?

我有一个jsp登录页面:

<login-config>
    <auth-method>FORM</auth-method>
    <form-login-config>
        <form-login-page>/core/login.jsp</form-login-page>
        <form-error-page>/core/login.jsp</form-error-page>
    </form-login-config>
</login-config>

在我的JSF页面(facelet)中,如果单击非Ajax按钮,我将被重定向到login.jsp。如果我单击一个Ajax按钮,它将保留在同一个JSF页面上。但是,在这两种情况下,我添加到JSP登录页面的调试代码都将显示在控制台中。

===

我使用facelet而不是jsp重写了登录页面

<login-config>
    <auth-method>FORM</auth-method>
    <form-login-config>
        <form-login-page>/facelets/login.jsf</form-login-page>
        <form-error-page>/facelets/login.jsf</form-error-page>
    </form-login-config>
</login-config>

我添加了一个AjaxLoginListener:

public class AjaxLoginListener implements PhaseListener {

        @Override
        public PhaseId getPhaseId() {
    //        return PhaseId.ANY_PHASE;
            return PhaseId.RESTORE_VIEW;
        }

        @Override
        public void beforePhase(PhaseEvent event) {
            System.out.println("    **** AjaxLoginListener: Before Phase: " + event.getPhaseId());
            // NOOP.
        }

        @Override
        public void afterPhase(PhaseEvent event) {
            System.out.println("    **** AjaxLoginListener: After Phase: " + event.getPhaseId());
            FacesContext context = event.getFacesContext();
            HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
            String originalURL = (String) request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI);
            String loginURL = request.getContextPath() + "/facelets/login.jsf";
            System.out.println("    **** "+new java.sql.Timestamp(System.currentTimeMillis()) + " -- "
                    + this.getClass().getName()+" AjaxLoginListener: After Phase: originalURL: " + originalURL + " Login URL: "+loginURL);
            System.out.println("    **** AjaxLoginListener: After Phase: request.getRequestURI() " +request.getRequestURI());

            System.out.println("    **** "+new java.sql.Timestamp(System.currentTimeMillis()) + " -- "
                    + this.getClass().getName()+" AjaxLoginListener: After Phase: isAjaxRequest " +context.getPartialViewContext().isAjaxRequest());

            if (context.getPartialViewContext().isAjaxRequest()
                    && originalURL != null
                    && loginURL.equals(request.getRequestURI()))
            {
                System.out.println("    **** "+new java.sql.Timestamp(System.currentTimeMillis()) + " -- "
                        + this.getClass().getName()+" AjaxLoginListener: After Phase: AjaxRequest " + event.getPhaseId());
                try {
                    context.getExternalContext().redirect(originalURL);
                } catch (IOException e) {
                    e.printStackTrace();
                    throw new FacesException(e);
                }
            }
        }
    }

一旦我使用了facelet而不是jsp,我就可以调用监听器了。但是,它永远不会进入登录页面,因为对于Ajax请求,originalURL(RequestDispatcher.FORWARD_REQUEST_URI)始终为NULL。怎么了?

1 个答案:

答案 0 :(得分:0)

简单的解决方案是添加一个检查用户是否已登录,如果没有,则重定向到登录页面:

    @Override
    public void afterPhase(PhaseEvent event) {
        System.out.println("    **** AjaxLoginListener: After Phase: " + event.getPhaseId());
        FacesContext context = event.getFacesContext();
        HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
        HttpSession session = request.getSession();

//        String originalURL = (String) request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI);

        String loginURL = request.getContextPath() + "/facelets/login.dti";
        System.out.println("    **** "+new java.sql.Timestamp(System.currentTimeMillis()) + " -- "
                + this.getClass().getName()+" AjaxLoginListener: After Phase:  Login URL: "+loginURL);
        System.out.println("    **** AjaxLoginListener: After Phase: request.getRequestURI() " +request.getRequestURI());

        System.out.println("    **** "+new java.sql.Timestamp(System.currentTimeMillis()) + " -- "
                + this.getClass().getName()+" AjaxLoginListener: After Phase: isAjaxRequest " +context.getPartialViewContext().isAjaxRequest());

        if (context.getPartialViewContext().isAjaxRequest()
                && session.getAttribute("user") == null
                && loginURL.equals(request.getRequestURI()))
        {
            System.out.println("    **** "+new java.sql.Timestamp(System.currentTimeMillis()) + " -- "
                    + this.getClass().getName()+" AjaxLoginListener: After Phase: AjaxRequest " + event.getPhaseId());
            try {
                context.getExternalContext().redirect(loginURL);
            } catch (IOException e) {
                e.printStackTrace();
                throw new FacesException(e);
            }
        }

    }

但是,这里有一个明显的缺点,即登录后不会进入原始页面。