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

Posted

技术标签:

【中文标题】授权过滤器中的错误(JEE6)【英文标题】:Bug in authorization filter(JEE6) 【发布时间】:2011-08-05 14:18:08 【问题描述】:

我正在为我的 JEE6 应用程序编写一个授权过滤器,以便能够限制某些用户对某些页面的访问。由于某种原因,浏览器根本不显示任何页面(我只看到白色)。某处肯定有错误,但我不知道在哪里,我是 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 中),其中包含允许的页面以及一个将 .xml 的详细信息存储为对象的 bean:

<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 导航到某些页面,但我只看到白色。

更新 我做了一些更改,以允许未登录的用户查看某些页面,但我得到了 NPE:

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】:

如果您没有看到任何内容,则过滤器已阻止该请求。 IE。它既没有继续这条链,也没有转发或重定向请求。您的代码流不合逻辑。当当前用户为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 ...,并将三个重复的块重构为一个辅助方法。


更新:根据您的重定向循环问题,如果您的过滤器映射到通用 URL 模式,例如 /*涵盖 main.xhtml)而不是例如/secured/*,那么当当前请求的页面为main.xhtml时,你需要重定向请求,但你需要继续链。只要当前请求的页面是main.xhtml,您就可以通过跳过主要的if 检查来做到这一点。反正你不关心main.xhtml 的授权。

【讨论】:

我按照你说的做了,我的 getUserType 返回一个枚举,我用 switch 语句处理它。浏览器说有一个重定向循环。我在上面的更新中粘贴了对代码的最后更改 查看答案更新。修改您的 if 块。例如。 if (notInMainXhtml &amp;&amp; currentUser != null). 对不起,但我不确定我是否理解。如果说 if (currentUser != null) ,我删除了主要环境,现在我看不到白色,但我在这一行得到一个 NPE: switch (currentUser.getType()) 那是因为用户没有登录我认为我需要,如果 您需要将if (currentUser != null) 替换为if (notInMainXhtml &amp;&amp; currentUser != null)。如果请求的页面不是main.xhtmlnotInMainXhtml 应该是评估true 的条件。例如。 if (!pageRequested.endsWith("/main.xhtml") &amp;&amp; currentUser != null). 我这样做了 if(!pageRequested.contains("main.xhtml") && currentUser != null) 但如果我尝试导航到 main.xml,我仍然会得到重定向循环我被重定向到 main.xml 的任何其他页面,所以我再次看到重定向循环。另外我想提一下我的项目的起始页是 index.jsp 我不知道这是否会影响什么

以上是关于授权过滤器中的错误(JEE6)的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security中的多个预授权过滤器?

验证操作过滤器或授权过滤器的用户权限?

自定义授权过滤器在运行时出现异常

[Core]Asp.Net Core中的各种过滤器(授权资源操作结果异常)

[原创]SpringSecurity控制授权(鉴权)功能介绍

[Core]Asp.Net Core中的各种过滤器(授权资源操作结果异常)