【问题标题】:Check if session exists JSF检查会话是否存在 JSF
【发布时间】:2011-12-29 23:03:22
【问题描述】:

我有一个登录页面,其中有一个用户 bean 来验证一个人的用户名和密码。这个 Bean 是 Session Scoped 的。 如果有人写了一个 URL 并试图跳转登录页面,我该如何检查并将他重定向到登录页面?

另一方面。假设我已经登录并且正在工作,突然我出去了一会儿,我的会话到期了。当我返回并尝试与表单交互时,它会发送一条消息,提醒我会话到期。发生这种情况时如何再次重定向到登录表单?

提前致谢。希望我自己解释一下。

Mojarra 2.1.4、Tomcat 7、战斧 1.1.11

【问题讨论】:

    标签: session jsf jsf-2 viewexpiredexception


    【解决方案1】:

    如果有人写了一个 URL 并试图跳转登录页面,我该如何检查并将他重定向到登录页面?

    您似乎使用的是本地身份验证。在这种情况下,您需要实现servlet filter。 JSF 将会话范围的托管 bean 存储为 HttpSession 的属性,因此您可以在 doFilter() 方法中检查它:

    HttpServletRequest req = (HttpServletRequest) request;
    UserManager userManager = (UserManager) req.getSession().getAttribute("userManager");
    
    if (userManager != null && userManager.isLoggedIn()) {
        chain.doFilter(request, response);
    } else {
        HttpServletResponse res = (HttpServletResponse) response;
        res.sendRedirect(req.getContextPath() + "/login.xhtml");
    }
    

    将此过滤器映射到覆盖受保护页面的 URL 模式,例如/app/*.


    当我返回并尝试与表单交互时,它会发送一条消息提醒我会话到期。发生这种情况时如何再次重定向到登录表单?

    我知道这涉及 Ajax 请求?对于普通请求,您可以在web.xml 中使用<error-page>。如果在web.xml中给客户端设置状态保存方式如下

    <context-param>
        <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
        <param-value>client</param-value>
    </context-param>
    

    不是一个选项,那么你需要实现一个自定义的ExceptionHandler

    public class ViewExpiredExceptionHandler extends ExceptionHandlerWrapper {
    
        private ExceptionHandler wrapped;
    
        public ViewExpiredExceptionHandler(ExceptionHandler wrapped) {
            this.wrapped = wrapped;
        }
    
        @Override
        public void handle() throws FacesException {
            FacesContext facesContext = FacesContext.getCurrentInstance();
    
            for (Iterator<ExceptionQueuedEvent> iter = getUnhandledExceptionQueuedEvents().iterator(); iter.hasNext();) {
                Throwable exception = iter.next().getContext().getException();
    
                if (exception instanceof ViewExpiredException) {
                    facesContext.getApplication().getNavigationHandler().handleNavigation(facesContext, null, "viewexpired");
                    facesContext.renderResponse();
                    iter.remove();
                }
            }
    
            getWrapped().handle();
        }
    
        @Override
        public ExceptionHandler getWrapped() {
            return wrapped;
        }
    
    }
    

    (请注意,此特定示例导航到 viewexpired,因此它需要 /viewexpired.xhtml 作为错误页面)

    以上需要通过以下ExceptionHandlerFactory实现烘焙:

    public class ViewExpiredExceptionHandlerFactory extends ExceptionHandlerFactory {
    
        private ExceptionHandlerFactory parent;
    
        public ViewExpiredExceptionHandlerFactory(ExceptionHandlerFactory parent) {
            this.parent = parent;
        }
    
        @Override
        public ExceptionHandler getExceptionHandler() {
            return new ViewExpiredExceptionHandler(parent.getExceptionHandler());
        }
    
    }
    

    这又需要在faces-config.xml注册如下:

    <factory>
        <exception-handler-factory>com.example.ViewExpiredExceptionHandlerFactory</exception-handler-factory>
    </factory>
    

    【讨论】:

    • 我对此有点怀疑。我被要求添加一个显示“转到主页”的 commandLink,但是当我单击它时,它首先转到 ViewExpired 页面,然后我必须再次单击才能转到主页。如何在不双击 commandLink 的情况下直接进入主页?
    • 使它成为一个普通的&lt;h:outputLink&gt;,而不是发送一个新的 GET 请求而不需要查看状态。您不需要通过 POST 提交任何数据,对吧?
    • 解决了问题,但又出现了一个问题。如果我留在登录页面,ViewExpiredException 也会发生。如何避免?
    • 显然该页面是从浏览器缓存而不是从服务器提供的。您需要告诉浏览器不要缓存这些页面。您可以使用过滤器来做到这一点,另请参阅stackoverflow.com/q/7840789/157882
    • 好的。阅读。所以我必须把这个过滤器放在 UserBean 或哪里?它是一个单独的类吗?
    【解决方案2】:

    如果您正在实现自己的系统,您可以为用户添加一个名为 session 的属性或其他任何内容。该属性可以是boolean,因此每当会话开始时,您都可以将此属性设置为true。编写一个名为permission的方法,例如:

    public void permission() throws IOException {
    
            if(userStatelessBean.getSession() == false) {
                System.out.println("*** The user has no permission to visit this page. *** ");
                ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
                context.redirect("login.xhtml");
            } else {
                System.out.println("*** The session is still active. User is logged in. *** ");
            }
        }
    

    在您想要限制的每个 jsf 页面(对于此示例)上,您可以在页面的最开头添加以下代码:

    <f:metadata>
         <f:event type="preRenderView" listener="#{sesija.permission()}"/>
    </f:metadata>
    

    这要做的是在渲染页面之前调用对象名称为 sesija 的 JSF ManagedBean,并检查您在指定方法中创建的规则是否满足。

    我希望你觉得这很有用,

    谢谢。

    【讨论】:

    • 紫外线因为这有助于我管理权限,但这并没有回答真正的问题(管理过期视图)
    猜你喜欢
    • 2011-06-10
    • 2018-04-04
    • 2013-02-26
    • 2013-05-22
    • 2011-02-18
    • 2012-10-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多