授权过滤器中的错误(JEE6)

时间:2011-04-14 14:15:52

标签: java security java-ee java-ee-6 servlet-filters

我正在为我的JEE6应用程序编写授权过滤器,以便能够限制对某些页面的某些用户的访问。由于某种原因,浏览器根本不显示任何页面(我只看到白色)。某处有一个bug,但我不知道在哪里,我是JEE6安全新手,我正在尝试以最简单的方式实现我的身份验证机制。

这是我的源代码

过滤器:

public class RestrictPageFilter implements Filter {

    private FilterConfig fc;
    private InputStream in;
    private Access access;

    public void init(FilterConfig filterConfig) throws ServletException {
        // The easiest way to initialize the filter
        fc = filterConfig;

        // Prepare the parsing
        try {
            in = Thread.currentThread().getContextClassLoader()
                    .getResourceAsStream("allowedpages.xml");
            Access access = (Access) JAXBContext.newInstance(Access.class)
                    .createUnmarshaller().unmarshal(in);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
    }

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {

        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;
        HttpSession session = req.getSession(true);
        String pageRequested = req.getRequestURL().toString();

        // Get the value of the current logged user
        Role currentUser = (Role) session.getAttribute("userRole");
        if (currentUser != null) {
            if (currentUser.getType().equals("BUYER")) {
                List<String> buyerPages = access.getBuyer().getPages();
                for (String s : buyerPages) {
                    if (pageRequested.contains(s)) {
                        chain.doFilter(request, response);
                    } else {
                        resp.sendRedirect("main.xml");
                    }
                }
            } else if (currentUser.getType().equals("SELLER")) {
                List<String> buyerPages = access.getSeller().getPages();
                for (String s : buyerPages) {
                    if (pageRequested.contains(s)) {
                        chain.doFilter(request, response);
                    } else {
                        resp.sendRedirect("main.xml");
                    }
                }
            } else if (currentUser.getType().equals("ADMINISTRATOR")) {
                List<String> buyerPages = access.getAdministrator().getPages();
                for (String s : buyerPages) {
                    if (pageRequested.contains(s)) {
                        chain.doFilter(request, response);
                    } else {
                        resp.sendRedirect("main.xml");
                    }
                }
            }
        }
    }

    public void destroy() {
        // Not needed
    }
}

为了支持这个过滤器,我使用一个.xml文件(位于WEB-INF / classes中),该文件包含允许的页面以及一个bean,用于存储.xml的详细信息作为对象:

<access>
    <buyer>
        <page>buyoffer.xhtml</page>
        <page>faq.xhtml</page>
        <page>index.jsp</page>
        <page>login.xhtml</page>
        <page>main.xhtml</page>
        <page>registrationSucceded.xhtml</page>     
    </buyer>
    <seller>
        <page>sellerpanel.xhtml</page>
        <page>faq.xhtml</page>
        <page>index.jsp</page>
        <page>login.xhtml</page>
        <page>main.xhtml</page>
        <page>registrationSucceded.xhtml</page>     
    </seller>
    <administrator>
        <page>sellerpanel.xhtml</page>
        <page>faq.xhtml</page>
        <page>index.jsp</page>
        <page>login.xhtml</page>
        <page>main.xhtml</page>
        <page>registrationSucceded.xhtml</page>     
    </administrator>
</access>

-

package simplebeans;

import java.util.List;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Access {

    @XmlElement
    private User buyer;

    @XmlElement
    private User seller;

    @XmlElement
    private User administrator;

    public User getBuyer() {
        return buyer;
    }

    public User getSeller() {
        return seller;
    }

    public User getAdministrator() {
        return administrator;
    }

    @XmlRootElement
    public static class User {

        @XmlElement(name="page")
        private List<String> pages;

        public List<String> getPages() {
            return pages;
        }

    }

}

这是我将过滤器添加到web.xml文件的方式:

<!--Page restriction filter -->
    <filter>
        <filter-name>restrict</filter-name>
        <filter-class>filters.RestrictPageFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>restrict</filter-name>
        <url-pattern>*.xhtml</url-pattern>
    </filter-mapping>

您认为我在浏览器中只看到白色的原因是什么? 我尝试使用URL导航到某些页面,但我只看到白色。

更新的 我做了一些更改,以便能够允许未登录的用户看到一些页面,但我得到了一个N​​PE:

doFilter方法的更改:

public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {

        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;
        HttpSession session = req.getSession(true);
        String pageRequested = req.getRequestURL().toString();

        // Get the value of the current logged user
        Role currentUser = (Role) session.getAttribute("userRole");
        boolean authorized = false;

        if (!pageRequested.contains("main.xhtml") && currentUser != null) {

            switch (currentUser.getType()) {
            case BUYER:
                for (String s : access.getBuyer().getPages()) {
                    if (pageRequested.contains(s)) {
                        authorized = true;
                    }
                }
                break;
            case SELLER:
                for (String s : access.getSeller().getPages()) {
                    if (pageRequested.contains(s)) {
                        authorized = true;
                    }
                }
                break;
            case ADMINISTRATOR:
                for (String s : access.getAdministrator().getPages()) {
                    if (pageRequested.contains(s)) {
                        authorized = true;
                    }
                }
                break;
            }
        }
        else {
            for (String s : access.getVisitor().getPages()) {
                if (pageRequested.contains(s)) {
                    authorized = true;
                }
            }
        }


        if (authorized || pageRequested.contains("main.xhtml")) {
            chain.doFilter(request, response);
        } else {
            resp.sendRedirect("main.xhtml");
        }
    }

xml文件的更改:

<visitor>
        <page>faq.xhtml</page>      
        <page>login.xhtml</page>
        <page>main.xhtml</page> 
        <page>registration.xhtml</page>
        <page>registrationbuyer.xhtml</page>    
        <page>registrationseller.xhtml</page>
    </visitor>

对Access bean所做的更改:

@XmlElement
    private User visitor;

public User getVisitor() {
        return visitor;
    }

1 个答案:

答案 0 :(得分:3)

如果您没有看到任何内容,则过滤器已阻止该请求。即它既没有继续链,也没有转发或重定向请求。你的代码流是不合逻辑的。当前用户为null或当前用户没有任何这些角色时,您也应该进行重定向。您还应该在整个过滤器代码中有效地呼叫chain.doFilter()response.sendRedirect() 一次。现在你在循环中为每个页面多次调用它们。那些方法调用不会神奇地中止for循环。

我建议重写主if块,如下所示

   boolean authorized = false;

   if (currentUser != null) {
        if (currentUser.getType().equals("BUYER")) {
            for (String s : access.getBuyer().getPages()) {
                if (pageRequested.contains(s)) {
                    authorized = true;
                    break;
                }
            }
        } else if (currentUser.getType().equals("SELLER")) {
            for (String s : access.getSeller().getPages()) {
                if (pageRequested.contains(s)) {
                    authorized = true;
                    break;
                }
            }
        } else if (currentUser.getType().equals("ADMINISTRATOR")) {
            for (String s : access.getAdministrator().getPages()) {
                if (pageRequested.contains(s)) {
                    authorized = true;
                    break;
                }
            }
        }
    }

    if (authorized) {
        chain.doFilter(request, response);
    } else {
        resp.sendRedirect("main.xhtml");
    }

我个人也将CurrentUser#getType()设为enum,以便您可以使用switch代替if else if else if else ...并将三个重复的块重构为单个辅助方法


更新:根据您的重定向循环问题,如果您的过滤器映射到/*之类的通用网址格式(涵盖main.xhtml而不是例如/secured/*,那么当当前请求的页面为main.xhtml时,您需要重定向请求,但您需要继续链接。您可以通过在当前请求的页面为if时跳过主main.xhtml检查来执行此操作。无论如何,您都不关心main.xhtml的授权。