HttpServletRequestWrapper 删除的参数仍然显示

Posted

技术标签:

【中文标题】HttpServletRequestWrapper 删除的参数仍然显示【英文标题】:HttpServletRequestWrapper removed parameter still showing up 【发布时间】:2013-01-30 23:33:37 【问题描述】:

我正在尝试使用 java/jsp 中的过滤器过滤出名为“原因”的查询参数。

基本上,过滤器的作用是确保用户输入了查看页面的“原因”。如果他们没有,它需要将他们重定向到“输入原因”页面。一旦他们输入了一个有效的理由,他们就可以继续访问他们请求的页面。

所以它的基本原理是有效的。但是,“原因”是通过查询参数(即 GET 参数)发送的。一旦用户选择了一个原因,原因参数就会被转发到他们想要查看的页面。这是一个问题,因为检查参数是否存在是过滤器确定用户是否可以继续前进的主要方式之一。

我已经尝试扩展HttpServletRequestWrapper,并覆盖了一堆方法(即getPameter 等)以删除“原因”参数。但是,我无法看到该参数被删除。一旦过滤器转发到请求的页面,“原因”参数始终作为 GET 参数在查询字符串(即浏览器 url 栏中的 url)中。

我的过滤器类看起来像:

public final class AccessRequestFilter implements Filter 

    public class FilteredRequest extends HttpServletRequestWrapper 

        public FilteredRequest(ServletRequest request) 
            super((HttpServletRequest)request);
        

        @Override
        public String getParameter(String paramName) 
            String value = super.getParameter(paramName);

            if ("reason".equals(paramName)) 
                value = null;
            

            return value;
        

        @Override
        public String[] getParameterValues(String paramName) 
            String[] values = super.getParameterValues(paramName);

            if ("reason".equals(paramName)) 
                values = null;
            

            return values;
        

        @Override
        public Enumeration<String> getParameterNames() 
            return Collections.enumeration(getParameterMap().keySet());
        

        @Override
        public Map<String, String[]> getParameterMap()             
            Map<String, String[]> params = new HashMap<String, String[]>();
            Map<String, String[]> originalParams = super.getParameterMap();

            for(Object o : originalParams.entrySet()) 
                Map.Entry<String, String[]> pairs = (Map.Entry<String, String[]>) o;
                params.put(pairs.getKey(), pairs.getValue());
            

            params.remove("reason");

            return params;
        

        @Override
        public String getQueryString() 
            String qs = super.getQueryString();

            return qs.replaceAll("reason=", "old_reason=");
        

        @Override
        public StringBuffer getRequestURL() 
            String qs = super.getRequestURL().toString();

            return new StringBuffer( qs.replaceAll("reason=", "old_reason=") );
        
    

    private FilterConfig filterConfig = null;  
    private static final Logger logger = MiscUtils.getLogger();

    public void init(FilterConfig filterConfig) throws ServletException   
        this.filterConfig = filterConfig;  
      

    public void destroy()   
        this.filterConfig = null;  
      

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException   
        logger.debug("Entering AccessRequestFilter.doFilter()");

        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        HttpSession session = httpRequest.getSession();

        boolean canView = false;
        long echartAccessTime = 0L;
        String demographicNo = "";
        String reason = "";
        Date current = new Date();

        String user_no = (String) session.getAttribute("user");

        ProgramProviderDAO programProviderDAO = (ProgramProviderDAO)SpringUtils.getBean("programProviderDAO");
        ProgramQueueDao programQueueDao = (ProgramQueueDao)SpringUtils.getBean("programQueueDao");

        // Check to see if user has submitted a reason
        reason = request.getParameter("reason");
        demographicNo = request.getParameter("demographicNo");
        Long demographicNoAsLong = 0L;
        try 
            demographicNoAsLong = Long.parseLong( demographicNo );
         catch (Exception e) 
            logger.error("Unable to parse demographic number.", e);
        

        if (reason == null) 
            // If no reason was submitted, see if user still has time remaining on previous submission (if there was one)
            try 
                echartAccessTime = (Long)session.getServletContext().getAttribute("echartAccessTime_" + demographicNo);
             catch (Exception e) 
                logger.warn("No access time found");
            

            if (current.getTime() - echartAccessTime < 30000) 
                canView = true;
            
         else if (!reason.equals("")) 
            // TODO: validate reason
            canView = true;
            session.getServletContext().setAttribute("echartAccessTime_" + demographicNo, current.getTime());
            String ip = request.getRemoteAddr();
            // Log the access request and the reason given for access
            LogAction.addLog(user_no, "access", "eChart", demographicNo, ip, demographicNo, reason);
        

        if (!canView) 
            // Check if provider is part of circle of care
            List<Long> programIds = new ArrayList<Long>();

            List<ProgramQueue> programQueues = programQueueDao.getAdmittedProgramQueuesByDemographicId( demographicNoAsLong );
            if (programQueues != null && programQueues.size() > 0) 
                for (ProgramQueue pq : programQueues) 
                    programIds.add( pq.getProgramId() );
                

                List<ProgramProvider> programProviders = programProviderDAO.getProgramProviderByProviderProgramId(user_no, programIds);

                if (programProviders != null && programProviders.size() > 0) 
                    canView = true;
                
            
        

        String useNewCaseMgmt;
        if((useNewCaseMgmt = request.getParameter("newCaseManagement")) != null )      
            session.setAttribute("newCaseManagement", useNewCaseMgmt); 
            ArrayList<String> users = (ArrayList<String>)session.getServletContext().getAttribute("CaseMgmtUsers");
            if( users != null ) 
                users.add(request.getParameter("providerNo"));
                session.getServletContext().setAttribute("CaseMgmtUsers", users);
            
        
        else 
            useNewCaseMgmt = (String)session.getAttribute("newCaseManagement");             
        

        String requestURI = httpRequest.getRequestURI();
        String contextPath = httpRequest.getContextPath();

        if (!canView && !requestURI.startsWith(contextPath + "/casemgmt/accessRequest.jsp")) 
            httpResponse.sendRedirect(contextPath + "/casemgmt/accessRequest.jsp?" + httpRequest.getQueryString());
            return;
        

        logger.debug("AccessRequestFilter chainning");
        chain.doFilter( new FilteredRequest(request), response);
    

过滤器设置为拦截所有进入名为casemgmt 的子目录的请求和转发。 web.xml 中的过滤器是这样的:

<filter>
        <filter-name>AccessRequestFilter</filter-name>
        <filter-class>org.oscarehr.casemgmt.filter.AccessRequestFilter</filter-class>
    </filter>
...
<filter-mapping>
        <filter-name>AccessRequestFilter</filter-name>
        <url-pattern>/casemgmt/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
    </filter-mapping>

有人知道我如何才能真正删除“原因”参数吗?

【问题讨论】:

当您说“查询字符串”时,您到底是什么意思?您在浏览器的地址栏中看到的那个?顺便说一句,您的getRequestURL() 覆盖是不必要的。它根本不包含查询字符串部分。 啊..是的,我越来越绝望了,所以我开始实现一堆我可能不需要的方法。我已经澄清了帖子中查询字符串的含义。谢谢。 嗯好的。为什么你认为包装和操作 HTTP servlet 请求会影响浏览器地址栏中的 URL?只有重定向才能做到这一点。 基本上,我只需要“原因”参数即可消失或使用不同的名称。所以我不能只使用doFilter 并提供一个包装好的请求吗?我必须重定向? 好的,我试试看。谢谢@BalusC 【参考方案1】:

在服务器端包装和操作HttpServletRequest 绝对不会神奇地影响您在浏览器地址栏中看到的URL。该 URL 保持原样,因为它是浏览器用来请求所需资源的 URL。包装后的请求只会影响在过滤器之后对同一请求运行的服务器端代码。

如果您想更改浏览器地址栏中的 URL,那么您应该将重定向发送到所需的 URL。

基本上,

if (reasonParameterIsIn(queryString)) 
    response.sendRedirect(requestURL + "?" + removeReasonParameterFrom(queryString));
    return;

【讨论】:

但是为什么原因参数(在被过滤器捕获之前作为表单中的 POST 参数发送)在 url 中显示为 GET 参数? 显然它出现在&lt;form action&gt; URL中,或者在重定向期间被另一个过滤器添加。 嗯...奇怪。我看不到任何地方,但是有很多bakc来回,所以这是可能的。无论如何,感谢您的帮助,我现在可以做我想做的事了。干杯@BalusC!

以上是关于HttpServletRequestWrapper 删除的参数仍然显示的主要内容,如果未能解决你的问题,请参考以下文章

使用 HTTPServletRequestWrapper 包装请求参数

JavaWeb:HttpServletRequestWrapper

JavaWeb:HttpServletRequestWrapper

使用HttpServletRequestWrapper重写Request请求参数

HttpServletRequestWrapper 删除的参数仍然显示

HttpServletRequestWrapper模拟实现分布式Session