1

我正在使用 JSF 1.2 开发一个需要用户登录的小页面。用户可能具有三个角色之一,我应该验证给定用户是否可以访问给定角色的页面。

假设管理员是唯一可以访问交易报告的人。在 ViewTransactionReportBean 默认构造函数中,我正在验证这一点:

HttpSession session = (HttpSession)FacesContext.getCurrentInstance().getExternalContext().getSession(false);
    LoginBean lb = null;
    try {
        lb = (LoginBean)session.getAttribute("loginBean");
        char role = lb.getRole();
        if(role!='A') 
            //Throw an exception to invalidate access
    }//catch here both invalid user or null pointer (not logged in) exceptions

这个 bean 是请求范围,所以它应该加载我提出的每个 Http 请求,对吗?

让我们测试一下这个场景:我以管理员身份登录。我点击查看交易报告页面。我可以看到报告。我点击主页。我单击注销(带逻辑):

public String logOut() {session.invalidate(); return "success";}

注销后(然后返回登录页面),我通过在浏览器中输入 URL 直接访问 ../faces/viewTransactionReport.jsp。我没有显示错误消息,而是看到了整个报告,这正是我在单击主页之前离开它的最后一个状态(注销之前)。直到我刷新页面 (F5),我才收到错误消息,指出我没有登录或我没有权限。

在我尝试调试后,当我直接在浏览器中输入 URL 时,我注意到甚至没有调用 bean 构造函数。

但我不知道为什么。

4

1 回答 1

2

我注意到甚至没有调用 bean 构造函数。

该页面显然是从浏览器缓存中请求的,而不是直接从服务器请求的。执行硬重新加载 (Ctrl+F5) 应该让浏览器真正向服务器发送 HTTP 请求。您可以在浏览器的内置 HTTP 流量监视器中跟踪这一点(在 Chrome/Firefox>=23/IE>=9 中按 F12)。

您实际上应该指示您的浏览器不要缓存受限页面。您可以通过在doFilter()方法中使用以下逻辑创建一个简单的 servlet 过滤器来实现:

@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
    HttpServletResponse response = (HttpServletResponse) res;
    response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
    response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
    response.setDateHeader("Expires", 0); // Proxies.
    chain.doFilter(req, res);
}

如果您将此过滤器映射到覆盖受限页面(可能是整个/faces/*?)的 URL 模式上,那么它应该可以为您解决问题:

<filter>
    <filter-name>noCacheFilter</filter-name>
    <filter-class>com.example.NoCacheFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>noCacheFilter</filter-name>
    <url-pattern>/faces/*</url-pattern>
</filter-mapping>
于 2013-11-07T16:11:49.290 回答