如何按顺序调用Servlet和Filter

3

你好,我正在开发一个Web应用程序,在调用web.xml中的servlet时遇到了问题。

这是我的web.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">

     <servlet>
            <servlet-name>FileServlet</servlet-name>
            <servlet-class>com.tpg.fileserver.FileServlet</servlet-class>
     </servlet>
    <servlet-mapping>
            <servlet-name>FileServlet</servlet-name>
            <url-pattern>/*</url-pattern>
        </servlet-mapping>
    <filter>
            <filter-name>AuthorizationFilter</filter-name>
            <filter-class>com.tpg.fileserver.AuthorizationFilter</filter-class>
      </filter>
      <filter-mapping>
            <filter-name>AuthorizationFilter</filter-name>
            <url-pattern>/*</url-pattern>
      </filter-mapping>

  </web-app>

问题是,当我试图运行我的应用程序时,我希望先运行授权过滤器,然后再运行文件Servlet。现在发生的情况与我想要的相反。我还尝试过将文件Servlet设置为0,但没有起作用。下面是我的Filter类代码。
public class AuthorizationFilter implements Filter  {

    private static final String kNotAuthorizedUrl = "/NotAuthorized.html";
    private static final String kTrustedHostsFileName = "trusted_hosts.txt";
    private static final String kPublicFilesFileName = "public_files.txt";

    private static final String TRUSTED_HOSTS = "TRUSTED_HOSTS";
    private static final String PUBLIC_FILES = "PUBLIC_FILES";
    private static Properties itsProperties = null;
    public static final String kPropertySingleSignOnURL = "sso-url";
    private static final String kPropertiesFileName = "metadata.properties";
    private static boolean itsInitialized = false;

    private static synchronized void initialize() {
        if (!itsInitialized) {
            try {
                ProductMetadataAPI.setProduct(Version.kProductName, Version.kPhysical);
                System.out.println("Inside Initialize");
                PersistenceAPI.isDebugging = true;
                JNDIConnectionFactory connFactory = new JNDIConnectionFactory("DataSource"); // IDB

                SingleSignOnAuthenticator.setAuthenticationUrl(ConfigurationUtils.getProperties().getProperty(kPropertySingleSignOnURL));

                SecurityAPI.setSecurity(
                    SecurityAPI.makeSecurity(
                        new StandardFactory(),
                        new PersistenceRepository(connFactory),
                        new CommonsBase64Codec(),
                        new SingleSignOnAuthenticator()));

                itsInitialized = true;
            } catch (Throwable e) {
                LoggerClass.logErr(e);
            }
        }
    }

    private void requestAuthentication(HttpServletResponse response) {
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.addHeader("WWW-Authenticate", "BASIC Realm=\"Single Sign-on\"");
        LoggerClass.logInfoMsg("SSO not set. redirecting to siteminder......");
    }


    public void doFilter(ServletRequest inRequest, ServletResponse inResponse, FilterChain chain) throws IOException, ServletException {
        try {
            HttpServletRequest request = (HttpServletRequest) inRequest;
            HttpServletResponse response = (HttpServletResponse) inResponse;
            System.out.println("Before Setting Serervlet Context");
            ConfigurationUtils.setCurrentServletContext(request.getSession().getServletContext());
            System.out.println("After Setting Serervlet Context");
            initialize();

            if (request instanceof HttpServletRequest && (request.getMethod().equals("GET") || request.getMethod().equals("POST"))) {
                String remoteHost = "", authorization = "", userName = "", password = "";
                HttpServletRequest r = (HttpServletRequest)request;
                Enumeration<String> e = r.getHeaderNames();
                while (e.hasMoreElements()) {
                    String headerName = e.nextElement();
                    LoggerClass.logInfoMsg(headerName + "=" + r.getHeader(headerName));
                }
                LoggerClass.logDebugMsg("Proxy-Client-IP is :" + r.getHeader("Proxy-Client-IP"));
                LoggerClass.logDebugMsg("Remote-Address-IP is :" + r.getRemoteAddr());


                remoteHost = r.getHeader("Proxy-Client-IP");
                if (remoteHost == null) {
                    remoteHost = r.getRemoteAddr();
                    LoggerClass.logDebugMsg("Remote-Address-IP ["+remoteHost + "] is requesting " + r.getRequestURI());
                }else{
                    LoggerClass.logDebugMsg("Proxy-Client-IP ["+remoteHost + "] is requesting " + r.getRequestURI());
                }

                authorization = r.getHeader("Authorization");
                if (authorization != null) {
                    final int index = authorization.indexOf(' ');
                    if (index > 0) {
                        final String[] credentials = StringUtils.split(new String(Base64.decodeBase64(authorization.substring(index))), ':');

                        if (credentials.length == 2) {
                            userName = credentials[0].toUpperCase();
                            password = credentials[1];
                        }
                    }
                }

                if (isSiteminderAuthenticationPresent(r)) {
                    LoggerClass.logInfoMsg("Inside Siteminder Logic ......");
                    chain.doFilter(request, response);
                    return;
                } else if (isPublic(request) || isTrusted(remoteHost)) {
                    LoggerClass.logInfoMsg("Inside Public/Trusted Host Logic ......");
                    chain.doFilter(request, response);
                    return;
                } else if (!isBasicAuthenticationPresent(userName, password)) {
                    LoggerClass.logInfoMsg("Failed in Basic Authentication Present.....");
                    requestAuthentication(response);
                } else if (!isBasicAuthenticationValid(r.getSession(), userName, password)) {
                    LoggerClass.logInfoMsg("Failed in Basic Authentication Validation.....");
                    requestAuthentication(response);
                } else {
                    chain.doFilter(request, response);
                }
            }
            response.sendRedirect(request.getContextPath() + kNotAuthorizedUrl);
        } catch (Exception e) {
            LoggerClass.logErr(e);
            throw new RuntimeException(e);
        }
    }
}

以下是我的Servlet部分代码:
public class FileServlet extends HttpServlet
{
public FileServlet()
    {
         System.out.println("In fileServlet");
         this.itsRootDir = Common.getRequiredProperty(Common.kPropertyRootDir);
            // some business logic
    }
@Override public void doGet(HttpServletRequest inRequest, HttpServletResponse inResponse)
    throws ServletException, IOException
    {
        String theRelFileName = Common.extractFileName(inRequest, false);
        String theFileName = this.itsRootDir + theRelFileName;
        File theFile = new File(theFileName);
     //Some more Business Logic
}
}           

以下是我在应用程序日志中获取的Sysout日志。我注意到了一件奇怪的事情。首先,调用将转到文件Servlet,然后是授权过滤器,然后再次转到文件Servlet。
[8/8/14 0:54:05:109 EDT] 0000002b SystemOut     O In fileServlet
[8/8/14 0:54:05:161 EDT] 0000002b SystemOut     O In Authoriazation Filter
[8/8/14 0:54:05:232 EDT] 0000002b SystemOut     O In fileServlet

1
AuthorizationFilter 是做什么的?请展示一下。 - Sotirios Delimanolis
过滤器包装Servlets。它们可用于Servlet调用的前后 - 你能否发布您的Filter代码,因为我怀疑那可能是您的问题所在。请参阅此相关帖子以获取示例:https://dev59.com/dXM_5IYBdhLWcg3wlEBH - Romski
你可以改变servlet的url模式。我的意思是,当用户输入某个url模式(如“/*”)时,先重定向到过滤器类,如果他成功通过身份验证,则重定向到servlet,否则重定向到错误页面。 - SparkOn
1
那个日志在构造函数中。它将被调用一次。它不是请求-响应循环的一部分。 - Sotirios Delimanolis
我认为这与Servlet映射和过滤器映射使用相同的URL模式有关。没有特定原因,将通配符映射到过滤器不是一个好主意。此外,不要在doFilter方法中放置synchronized方法,因为它会导致性能问题。 - Brad
显示剩余12条评论
2个回答

1

filtersweb.xml中定义的顺序决定了它们在webapp启动时的初始化顺序。

servlets默认仅在首次HTTP请求其url-pattern时进行初始化。

因此,在这种情况下,首先会解析web.xml,并创建其中找到的每个Filter一次,并将其保存在服务器内存中。

现在,当来自/*等url模式的请求到达时,容器查找该模式并找到servlet的映射,然后初始化servlet。然后调用filter以处理请求。

要解决这个问题,您可以更改servlet的url模式。当用户输入像/*这样的url模式时,将其重定向到过滤器类,如果身份验证成功,则重定向到指定其他url模式的servlet,否则重定向到错误页面


嗨……目前我正试图在Websphere服务器上部署这个应用程序。在Weblogic服务器上,使用相同的配置它可以正常工作,但在Websphere应用程序中却出现问题。所以我的问题是,不同的应用服务器之间行为会有所不同吗? - Naman

0
上述问题的答案是,FileServlet中的构造函数在过滤器执行之前被调用。为了解决这个问题,我已经将构造函数改为公共方法,并在Servlet的doget()方法中调用它。在这个改变之后,过滤器首先被调用,然后才调用servlet。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接