52

I want to receive some information per request, so I think instead of having a function for each request and obtaining those information from requests separately, it's better to have a filter.
So every request shall pass that filter and I gain what I want.


The question is: How can I write a custom filter?
Suppose it is not like any predefined spring security filters and it is totally new.

Matin Kh
  • 5,192
  • 6
  • 53
  • 77

2 Answers2

49

You can use the standard Java filter. Just place it after authentication filter in web.xml (this means that it will go later in the filter chain and will be called after security filter chain).

public class CustomFilter implements Filter{

    @Override
    public void destroy() {
        // Do nothing
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res,
            FilterChain chain) throws IOException, ServletException {

            HttpServletRequest request = (HttpServletRequest) req;

            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

            Set<String> roles = AuthorityUtils.authorityListToSet(authentication.getAuthorities());
            if (roles.contains("ROLE_USER")) {
                request.getSession().setAttribute("myVale", "myvalue");
            }

            chain.doFilter(req, res);

    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {
        // Do nothing
    }

}

Fragment of web.xml:

<!-- The Spring Security Filter Chain -->
<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<!-- Your filter definition -->
<filter>
    <filter-name>customFilter</filter-name>
    <filter-class>com.yourcompany.test.CustomFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>customFilter</filter-name>
    <url-pattern>/VacationsManager.jsp</url-pattern>
</filter-mapping>

Also you can add handler that will be invoked after successfull login (you need to extend SavedRequestAwareAuthenticationSuccessHandler). Look here how to do this. And I think that this is even better idea.


UPDATED:
Or you can have this filter at the end of your security filters like this:

<security:filter-chain-map>
    <sec:filter-chain pattern="/**"
            filters="
        ConcurrentSessionFilterAdmin, 
        securityContextPersistenceFilter, 
        logoutFilterAdmin, 
        usernamePasswordAuthenticationFilterAdmin, 
        basicAuthenticationFilterAdmin, 
        requestCacheAwareFilter, 
        securityContextHolderAwareRequestFilter, 
        anonymousAuthenticationFilter, 
        sessionManagementFilterAdmin, 
        exceptionTranslationFilter, 
        filterSecurityInterceptorAdmin,
        MonitoringFilter"/> <!-- Your Filter at the End -->
</security:filter-chain-map>

And to have your filter, you may use this:

public class MonitoringFilter extends GenericFilterBean{
@Override
public void doFilter(ServletRequest request, ServletResponse response,
        FilterChain chain) throws IOException, ServletException {
    //Implement this Function to have your filter working
}
Gowtham
  • 11,853
  • 12
  • 43
  • 64
dimas
  • 6,033
  • 36
  • 29
  • As I was waiting for the answer, I came up with a solution. I added my filter (extended `GenericFilterBean`) at the end of my security filters. It is working just fine. But now, as I saw your answer, it sounds better to me. I'm giving a try to your solution. Hope it works too. I'll let you know the result. Thanks. – Matin Kh Aug 13 '12 at 07:05
  • Generally your answer is correct, but I have to modify it a bit. Thanks for your help. – Matin Kh Aug 13 '12 at 07:25
  • Ok. Modify my unswer and I will accept your changes. It will be interesting for me to know where I was wrong. – dimas Aug 13 '12 at 07:31
  • You were not wrong. Your answer is correct. I wanted to have my solution (which is pretty much similar to yours) be included here for later usage. – Matin Kh Aug 13 '12 at 07:34
  • 5
    Yes, your solution is good too. But in such case we need to define all filters (even default) and if we miss one then it will not be called. Am I right? – dimas Aug 13 '12 at 08:33
  • Not necessarily. You can have have your desired filters for different patterns. It is just like your solution, but, instead of having my filter introduced in `web.xml` I have it next to other required filters. Here I'm giving a general solution, but in fact, in my application and for _that_ pattern, there are two other filters next to my `monitoringFitler`. – Matin Kh Aug 13 '12 at 10:02
  • Is it possible to autowire a JPA repository into this custom filter? – Tayba Apr 16 '14 at 10:28
  • 1
    what does "standard java filter" mean? `javax.servlet.Filter`? – Andrew Tobilko Jul 09 '16 at 16:52
15

Just throwing this in the mix; how about using custom-filter inside http element:

<security:http auto-config="false" ...>
  ...
  <security:custom-filter position="FORM_LOGIN_FILTER" ref="MyCustomFilter" />
</security:http>
Ithar
  • 4,865
  • 4
  • 39
  • 40