从过滤器中排除网址的最简单方法是将您的过滤器映射到特定的模式。在早期开发阶段完成时,这是可行的,但是如果您修改生产环境中现有过滤器的URL模式,则必须重新映射所有现有的servlet URL才能达到目的,否则这可能是一个繁琐的过程。
在本教程中,我们将演示如何以编程方式向现有过滤器添加排除功能。
自定义过滤器是您可以控制的过滤器。即您拥有修改其源代码的所有权利。
假设我们有一个现有的Web应用程序,它通过LDAP来验证用户请求。所有servlet请求都通过映射到/ *的LDAPAuthenticationFilter传递,如下所示:
<filter>
<filter-name>LDAPAuthenticationFilter</filter-name>
<filter-class>com.programmer.gate.filters.LDAPAuthenticationFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LDAPAuthenticationFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
我们的过滤器只是验证请求,然后调用 chain.doFilter():
LDAPAuthenticationFilter.java
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
public class LDAPAuthenticationFilter implements Filter{
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
// Authenticate the request through LDAP
System.out.println("Authenticating the request through LDAP");
// Forward the request to the next filter or servlet in the chain.
chain.doFilter(req, resp);
}
public void init(FilterConfig filterConfig) throws ServletException {
}
public void destroy() {
// TODO Auto-generated method stub
}
}
现在,假设我们要创建一个需要简单数据库认证的servlet,并且不需要通过LDAP。我们首先考虑创建一个新过滤器并将其映射到新servlet的特定URL模式。
所以我们创建一个名为DatabaseAuthenticationFilter 的新过滤器,它简单地通过数据库验证请求,然后调用 chain.doFilter():
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class DatabaseAuthenticationFilter implements Filter{
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
// Authenticate the request through database then forward the request to the next filter or servlet in the chain
System.out.println("Authenticating the request through database");
chain.doFilter(req, resp);
}
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
public void destroy() {
// TODO Auto-generated method stub
}
}
我们在web.xml中定义我们的过滤器,以仅处理以/ DatabaseAuthenticatedServlet开头的特定URL :
<filter>
<filter-name>DatabaseAuthenticationFilter</filter-name>
<filter-class>com.programmer.gate.filters.DatabaseAuthenticationFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>DatabaseAuthenticationFilter</filter-name>
<url-pattern>/DatabaseAuthenticatedServlet/*</url-pattern>
</filter-mapping>
这里的问题是像/ DatabaseAuthenticatedServlet 这样的请求也会匹配根URL模式“/ *”,即我们的请求会通过2个认证过程:LDAP和数据库, 排序取决于哪个过滤器首先在web.xml下定义 。
为了解决这个问题,我们需要修改LDAPAuthenticationFilter,以便排除以/ DatabaseAuthenticatedServlet开头的URL 。 通常情况下,人们会静态检查doFilter()方法中的请求的servlet URL,并在发现后直接绕过认证过程。
这里我们更进一步,实现一个更动态的解决方案,它允许我们通过web.xml管理排除的URL 。
以下是将排除功能添加到LDAPAuthenticationFilter的步骤:
private List excludedUrls;
public void init(FilterConfig filterConfig) throws ServletException {
String excludePattern = filterConfig.getInitParameter("excludedUrls");
excludedUrls = Arrays.asList(excludePattern.split(","));
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
String path = ((HttpServletRequest) req).getServletPath();
if(!excludedUrls.contains(path))
{
// Authenticate the request through LDAP
System.out.println("Authenticating the request through LDAP");
}
// Forward the request to the next filter or servlet in the chain.
chain.doFilter(req, resp);
}
<filter>
<filter-name>LDAPAuthenticationFilter</filter-name>
<filter-class>com.programmer.gate.filters.LDAPAuthenticationFilter</filter-class>
<init-param>
<param-name>excludedUrls</param-name>
<!-- Comma separated list of excluded servlets -->
<param-value>/DatabaseAuthenticatedServlet,/UnAuthenticatedServlet</param-value>
</init-param>
</filter>
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
public class LDAPAuthenticationFilter implements Filter{
private List excludedUrls;
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
String path = ((HttpServletRequest) req).getServletPath();
if(!excludedUrls.contains(path))
{
// Authenticate the request through LDAP
System.out.println("Authenticating the request through LDAP");
}
// Forward the request to the next filter or servlet in the chain.
chain.doFilter(req, resp);
}
public void init(FilterConfig filterConfig) throws ServletException {
String excludePattern = filterConfig.getInitParameter("excludedUrls");
excludedUrls = Arrays.asList(excludePattern.split(","));
}
public void destroy() {
// TODO Auto-generated method stub
}
}
第三方过滤器是您无法控制的过滤器。即你不能修改他们的源代码。
在本节中,我们稍微修改我们的示例,并使用CAS认证而不是LDAP。这是我们如何在web.xml中定义我们的CAS认证过滤器:
<filter>
<filter-name>CAS Authentication Filter</filter-name>
<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
<init-param>
<param-name>casServerLoginUrl</param-name>
<param-value>https://localhost:8443/cas/login</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>localhost</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CAS Authentication Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
CAS认证是通过第三方库完成的,现在为了支持数据库认证,我们不能修改CAS的源代码,就像我们在前面的LDAP例子中所做的那样。
从第三方过滤器中排除URL的解决方案是使用新的自定义过滤器来包装它,该自定义过滤器仅添加排除功能并将过滤器逻辑委托给包装的类。
以下是将排除功能添加到CAS认证的步骤:
public class CASCustomAuthenticationFilter implements Filter{
private AuthenticationFilter casAuthenticationFilter = new AuthenticationFilter();
private List excludedUrls;
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
String path = ((HttpServletRequest) req).getServletPath();
if(!excludedUrls.contains(path))
{
// Authenticate the request through CAS
casAuthenticationFilter.doFilter(req,resp,chain);
}
// Forward the request to the next filter or servlet in the chain.
chain.doFilter(req, resp);
}
public void init(FilterConfig arg0) throws ServletException {
String excludePattern = filterConfig.getInitParameter("excludedUrls");
excludedUrls = Arrays.asList(excludePattern.split(","));
casAuthenticationFilter.init();
}
public void destroy() {
casAuthenticationFilter.destroy();
}
}
<filter>
<filter-name>CAS Authentication Filter</filter-name>
<filter-class>com.programmer.gate.filters.CASCustomAuthenticationFilter</filter-class>
<init-param>
<param-name>casServerLoginUrl</param-name>
<param-value>https:localhost:8443/cas/login</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>localhost</param-value>
</init-param>
<init-param>
<param-name>excludeUrls</param-name>
<param-value>/DatabaseAuthenticatedServlet</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CAS Authentication Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
http://blog.xqlee.com/article/419.html