Reputation: 1261
I see this in my Spring MVC app's web.xml
:
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
I'm trying to figure out why it's there and whether it's actually needed.
I found this explanation in the Spring docs but it doesn't help me make sense of it:
It seems to suggest that this component is the "glue" between the servlets defined in web.xml
and the components defined in the Spring applicationContext.xml
.
7.1 DelegatingFilterProxy
When using servlet filters, you obviously need to declare them in your
web.xml
, or they will be ignored by the servlet container. In Spring Security, the filter classes are also Spring beans defined in the application context and thus able to take advantage of Spring's rich dependency-injection facilities and lifecycle interfaces. Spring'sDelegatingFilterProxy
provides the link betweenweb.xml
and the application context.When using DelegatingFilterProxy, you will see something like this in the
web.xml
file:<filter> <filter-name>myFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>myFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Notice that the filter is actually a
DelegatingFilterProxy
, and not the class that will actually implement the logic of the filter. WhatDelegatingFilterProxy
does is delegate the Filter's methods through to a bean which is obtained from the Spring application context. This enables the bean to benefit from the Spring web application context lifecycle support and configuration flexibility. The bean must implementjavax.servlet.Filter
and it must have the same name as that in the filter-name element. Read the Javadoc for DelegatingFilterProxy for more information
So, if I take this out of my web.xml
, what will happen? My servlets won't be able to communicate with the Spring container?**
Upvotes: 126
Views: 85054
Reputation: 322
Let's split the name as "Delegating + Filter + Proxy".
DeletgatingFilterProxy
is simply a filter that acts as a proxy for a bunch of other filters, and that's why the name "FilterProxy" (Filter + Proxy). We'll see the reason for the word "Delegating" at the end.
To understand this, we must first understand two things about how a Spring Web application loads up.
@Component
)Before we see the answer, let's understand a simple code example
// Let's say our filter expects an object of this interface in its constructor
@Repository
public interface UserRepository implements JpaRepository<User, Long> {
}
@Component("MyCustomFilter")
public class MyCustomFilter implements Filter {
// This needs to be injected from Spring's Application Context.
private UserRepository userRepository;
public CustomFilter(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// Do something with the request.
}
}
In the above example, our MyCustomFilter
expects a UserRepository
object and wants it to be injected by Spring. If in case, we listed this filter in web.xml, the Servlet Container won't have any idea about how to create an object for UserRepository
interface and thus, it won't be able to create an object for our MyCustomFilter
class and the application will fail to start.
So, if we wish to use Spring's features in our filter, we can't list the filter in web.xml due to the order in which the Servlet Container and Spring Application Context loads up.
Instead of listing our filter classes (which leverages Spring's features) in web.xml directly, we will tell the DelegatingFilterProxy
to accept the request and pass the request to our custom filter.
We can do this in two steps.
MyCustomFilter
and tell it to load the DelegatingFiterProxy
class.<filter>
<filter-name>MyCustomFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>MyCustomFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-name>
to the @Component
annotation.@Component("MyCustomFilter")
public class MyCustomFilter implements Filter {
// ...
}
Thus all the requests will be passed to the DelegatingFilterProxy
by the Servlet Container and then, based on the filter-name
(MyCustomFilter), the DelegatingFilterProxy
picks the right bean from the Spring's Application Context and invokes its doFilter
method.
Since the DelegatingFilterProxy
acts as a proxy for our filter, and accepts the requests and passes (delegates) it to our filter, it is called DelegatingFilterProxy
.
References: Spring's doc
One last thing for the Nerds, from the doc (modified slightly)
the (servlet) container needs to register the Filter instances before the container can start up. However, Spring typically loads the Spring Beans after the Filter instances are registered.
Upvotes: 2
Reputation: 128829
Do you know what a Servlet Filter is and how it works? It's a very useful piece of the Servlet Spec, allowing us to apply AOP-like concepts to servicing of HTTP requests. Many frameworks use Filter implementations for various things, and it's not uncommon to find custom implementations of them because they're very simple to write and useful. In a Spring app, most of the stuff that your app can do is in your Spring beans. A Filter instance, though, is controlled by the Servlet container. The container instantiates, initializes, and destroys it. The Servlet Spec doesn't require any kind of Spring integration, though, so you're left with a really useful concept (Filters) with no convenient way of tying it to your Spring app and the beans that do the work.
Enter the DelegatingFilterProxy. You write a Filter implementation and make it a Spring bean, but instead of adding your own Filter class to the web.xml, you use the DelegatingFilterProxy, and give it the bean name of your filter in the Spring context. (If you don't explicitly provide a name, it uses the "filter-name".) Then at runtime, the DelegatingFilterProxy handles the complexity of finding the real implementation - the one you wrote and configured in Spring - and routing requests to it. So at runtime, it's as if you had listed your filter in the web.xml, but you get the benefit of being able to wire it like any other Spring bean.
If you take that filter mapping out of your web.xml, everything will continue working, but none of your URLs will be secured. (That's assuming the name "springSecurityFilterChain" accurately describes what it does.) That's because this mapping is filtering every incoming request and handing it off to a security filter that's defined in your Spring context.
Upvotes: 85
Reputation: 924
Its been a long time but I had the same question and I found this: https://www.javacodegeeks.com/2013/11/spring-security-behind-the-scenes.html
I tried to run my spring security project by removing the filter in question and also by adding it. What I found is if we add the filter, only then the call will redirect to required login page as defined in the spring-security configuration.
Hence, agreeing to @Ryan's answer.
Upvotes: 0
Reputation: 11625
Servlet filters are, in general, a Java WebApp concept. You can have servlet filters in any webapp, whether or not you use Spring framework in your application.
These filters can intercept requests before they reach the target servlet. You can implement common functionality, like authorization, in servlet filters. Once implemented, you can configure the filter in your web.xml to be applied to a specific servlet, specific request url patterns or all url patterns.
Modern web-apps can have dozens of such filters. Things like authorization, caching, ORM session management, and dependency injection are often implemented with the aid of servlet filter. All of these filters need to be registered in web.xml
.
Your servlet container creates instances of Filters declared in web.xml
and calls them at appropriate times (i.e., when servicing servlet requests). Now if you are like most of the Dependency Injection (DI) fans, you would likely say that creation of instances is what my DI framework (Spring) does better. Can't I get my servlet filters created with Spring so they are amenable to all DI goodness?
DelegatingFilterProxy
, so that Spring creates your filter instancesThis is where DelegatingFilterProxy
steps in. DelegatingFilterProxy
is an impelmentation of the javax.servlet.Filter
interface provided by Spring Framework. Once you configure DelegatingFilterProxy
in web.xml, you can declare the actual beans that do the filtering in your spring configuration. This way, Spring creates the instances of beans that do the actual filtering, and you can use DI to configure these beans.
Note that you need only a single DelegatingFilterProxy
declaration in web.xml
but you can have several filtering bean
s chained together in your application context.
Upvotes: 57
Reputation: 864
I have been perplexed by "springSecurityFilterChain" in web.xml and found this answer in springframework security document:
The
<http>
element encapsulates the security configuration for the web layer of your application. >It creates a FilterChainProxy bean named "springSecurityFilterChain" which maintains the stack of >security filters which make up the web security configuration [19]. Some core filters are always >created and others will be added to the stack depending on the attributes child elements which are >present. The positions of the standard filters are fixed (see the filter order table in the >namespace introduction), removing a common source of errors with previous versions of the framework >when users had to configure the filter chain explicitly in theFilterChainProxy bean. You can, of >course, still do this if you need full control of the configuration.
Here is the link http://docs.spring.io/spring-security/site/docs/3.0.x/reference/appendix-namespace.html
Upvotes: 0
Reputation: 2842
There's some kind of magic here, but at the end, everything is a deterministic program.
The DelegatingFilterProxy is a Filter as it was explained above, whose goal is "delegating to a Spring-managed bean that implements the Filter interface", that is, it finds a bean ("target bean" or "delegate") in your Spring application context and invokes it. How is it possible? Because this bean implements javax.servlet.Filter, its doFilter method is called.
Which bean is called? the DelegatingFilterProxy "Supports a "targetBeanName" [...], specifying the name of the target bean in the Spring application context."
As you saw in your web.xml that the bean's name is "springSecurityFilterChain".
So, in the context of a web application, a Filter instantiates a bean called "springSecurityFilterChain" in your application context and then delegate to it via the doFilter() method.
Remember, your application context is defined with ALL THE APPLICATION-CONTEXT (XML) files. For instance: applicationContext.xml AND applicationContext-security.xml.
So try to find a bean called "springSecurityFilterChain" in the latter...
...and probably you can't (for instance if you followed a tutorial or if you configured the security using Roo)
Here is the magic: there's a new element for configuring the security, something like
<http auto-config="true" use-expressions="true">
as it is allowed by http://www.springframework.org/schema/security/spring-security-3.0.xsd, will do the trick.
When Spring loads the application context using XML files, if it finds a element, it will try to set up the HTTP security, that is, a filter stack and protected URLs and to register the FilterChainProxy named "springSecurityFilterChain".
Alternatively, you can define the bean in the classic way, that is:
<beans:bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
But it's less recommended, since you need to do a lot of configuration (all the filters that you're going to use. And there are more than a dozen of them)
Upvotes: 132
Reputation: 597076
The thing is, servlet filters are managed by the servlet container, and not by spring. And you may need to inject some spring components into your filters.
So, if you need something like:
public class FooFilter {
@Inject
private FooService service;
public void doFilter(....) { .. }
}
then you need the delegating filter proxy.
Upvotes: 21
Reputation: 7522
You are right about 'glue' stuff. As written in JavaDocs of FilterChainProxy:
The FilterChainProxy is linked into the servlet container filter chain by adding a standard Spring DelegatingFilterProxy declaration in the application web.xml file.
Please see FIlterChainProxy section of blog Behind the Spring Security Namespace for an excellent explanation.
Upvotes: 1