Annoted, type-safe interceptors for Spring web controllers

Annotate security or other interceptors for your Spring web controllers, much like you normally annotate routes or endpoints.

@Before(@BeforeElement( MySecurityFilter.class )) @Controller public class MyController { @RequestMapping("/helloworld") @ResponseBody public String heyworld() { return "hey there big n blue"; } } To secure all the endpoints in your @Controller class, add a @Before annotation like this (you can also add it to individual methods for more granular control):

@Component public class MySecurityFilter implements BeforeHandler { @Override public Flow handle(HttpServletRequest request, HttpServletResponse response, HandlerMethod handler, String[] flags) throws Exception { //determine if this request is authorized, using daos or any other mechanism. //you have full access to Spring context and autowiring here //to halt this request and prevent execution of the controller, return Flow.HALT //you may also redirect to a login page here if desired return Flow.CONTINUE; } } Then create your implementing class for MySecurityFilter and make sure it's reachable by Spring:



Your security boundaries are easy to see in the controller file itself, just like mvc routes

Unlike Spring security boundaries, it is type-safe -- if you reorganize your packages, your security still works because it's defined in the file itself This is subjective, but IMO for the simple yet common use case of writing code that runs before your controllers, I find this to be much simpler to use and setup.

How to set it up

<dependencies> <dependency> <groupId>com.kastkode</groupId> <artifactId>springsandwich</artifactId> <version>[1.0.2,)</version> </dependency> </dependencies>

@ComponentScan(basePackages = {"com.kastkode.springsandwich.filter", "com.your-app-here.*"}) public class Main { ... }

More details on how to use SpringSandwich

import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Component; import org.springframework.web.method.HandlerMethod; import com.kastkode.springsandwich.filter.api.BeforeHandler; import com.kastkode.springsandwich.filter.api.Flow; @Component public class RestrictByRole implements BeforeHandler { @Override public Flow handle(HttpServletRequest request, HttpServletResponse response, HandlerMethod handler, String[] flags) throws Exception { System.out.println("RestrictByRole logic executed, checking for these roles"); if(flags != null) { for(String arg:flags) { System.out.println(arg); } } //or return Flow.HALT to halt this request and prevent execution of the controller //you may also wish to redirect to a login page here return Flow.CONTINUE; } }

@Before( @BeforeElement(RestrictByRole.class))

@Before( @BeforeElement(value = RestrictByRole.class, flags = {"admin", "manager"}) )

@Before({ @BeforeElement(IPWhiteListCheck.class), @BeforeElement(LoginWall.class), @BeforeElement(value = RestrictByRole.class, flags = {"admin", "manager"}) })

@After( @AfterElement(DoThisAfter.class) )

FAQ

How is SpringSandwich different from Spring AOP or Spring Security?

SpringSandwich is type-safe, whereas Spring AOP and Spring Security rely on String-based annotations which cannot be tested until runtime and which do not survive refactorings. Spring AOP furthermore uses global String expressions, making it sometimes less transparent about where advice is being applied (or even worse, silently NOT applied!). SpringSandwich is vastly simpler to use. This is of course hard to prove; you'll have to just try and compare for yourself. But you may wish to have a quick look at Spring AOP's documentation for comparison.

How is SpringSandwich different from a servlet filter?

It can be directly applied via annotations, and is thus type-safe and will survive refactorings Your interceptors have full access to the spring context. For instance, it is difficult to write a standard servlet filter that uses your daos to lookup a user because typically your daos require the spring context, which won't be accessible from a servlet filter. But in SpringSandwich, you have full access -- write your regular code like anywhere else. By re-using the routing information already defined in your controller instead of redundantly defininig elsewhere the routes to which it applies, SpringSandwich facilitates DRYer software with less room for error. In other words, it's a cleaner solution!

This has the following advantages over Spring Security:1. Include it in your project's pom.xml:2. In your application, tell Spring to pick up the library. For instance in Spring Boot you would add this annotation to your Main starting class:(Notice that we explicitly ComponentScan our Main package as well since we're overriding Spring Boot's default scanning.)A full implementation for an interceptor might look like this:Apply it to your controller as an annotation either at the class or the method (or both):You can also pass a list of strings for the interceptor to consider. Here the flags "admin" and "manager" are passed in to the RestrictByRole implementation methodYou can apply several interceptors in sequence like thisThere's also an After interceptor you can useMany common use cases have already been addressed in premade interceptors found in com/kastkode/springsandwich/filter/coldcuts/. Consider extending them as a starting point for your interceptorSpringSandwich has these main advantages over servlet filters: