CDI interceptor of HTTP Request and Header params – simple example
While developing and evolving a REST API, using Java EE , there are some cases where you would like to have ‘a look’ on the incoming HTTP request, specifically the header params, in a more fine grained (per case) way, rather than a Servlet Filter or the more specific ContainerRequestFilters.
One potential way, which I find in some cases very convenient is the addition of CDI interceptors along my JAXRS Resource implementation, that eventually have access to the incoming HTTP request and perform some ‘custom’ logic. As a developer I can fully control – where (in which paths) to intercept the request, by just adding or removing the custom annotation.With the introduction of Java EE 7, it is easier to mix ‘concerns’ , so you can easily inject the HTTP Request to plain CDI interceptors.
Below I am just documenting a very simple example, where I use a custom interceptor, to ‘intercept’ HTTP requests on a business REST API, in order to do some very specific custom Authentication logic. I am checking if the ‘user’ initiating the request in my REST API is in some specific custom role, that my system defines. Of course the overall example is just an example, but you get the idea.
In order to introduce such a component you need 2 things :
- introduce a custom annotation, that will be used for activating the interceptor, when it is defined
- implement the CDI interceptor.
- apply the annotation, on the paths/ resources of your rest api
The annotation interface
Nothing fancy here, just a custom run-time annotation, so we can use in order to ‘mark’ specific methods of our JAXRS API.
package gr.javapapo.sample.cdi; /** * Created by <a href="mailto:javapapo@mac.com">javapapo</a> on 24/09/15. */ import javax.enterprise.util.Nonbinding; import javax.interceptor.InterceptorBinding; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @InterceptorBinding @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) public @interface CheckRequest { @Nonbinding String role() default "ADMIN"; }
The implementation of the interceptor
Noteworthy points:
- the interceptor is ‘marked’ with our custom annotation – simple
- we @Inject the HttpServletReqest
- We apply some custom logic, based on the annotation details (I read any params on the definition)
- From the request I read the header and based on the annotation params – i do some basic logic
package gr.javapapo.sample.cdi; import javax.inject.Inject; import javax.interceptor.AroundInvoke; import javax.interceptor.Interceptor; import javax.interceptor.InvocationContext; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.NotAllowedException; /** * CDI interceptor for the {@linkplain CheckRequest} annotation * Created by <a href="mailto:javapapo@mac.com">javapapo</a> on 24/09/15. */ @Interceptor @CheckRequest public class CheckRequestInterceptor { @Inject HttpServletRequest request; @AroundInvoke public Object checkAccess(InvocationContext ctx) throws Exception { CheckRequest annotation = ctx.getMethod().getAnnotation(CheckRequest.class); String role = annotation.role(); String roleToken = request.getHeader("roleToken"); if(roleToken==null && !role.equals(roleToken)){ throw new NotAllowedException("Not allowed if your request does not have the roleToken header " + "or your role is not correct "); } return ctx.proceed(); } }
Applying the interceptor / annotation
Eventually, you can just annotate your @Path JAXRS resources and methods in order to ‘kick’ in your custom logic:
@Path("/status") public class StatusResource { /** * Returns a simple JSON object, regarding the app status, n * * @return Response <JsonObject> */ @GET @Produces(MediaType.APPLICATION_JSON) @CheckRequest(role="ADMIN") public Response getStatus() { JsonObject object = Json.createObjectBuilder() .add("status", "Status with CDI internceptor check,It Works at " + LocalDateTime.now().toString()) .build(); Response.ResponseBuilder repBuilder = Response.ok().entity(object); return repBuilder.build(); }
- You can find all the files in this very simple sample project on github.
Reference: | CDI interceptor of HTTP Request and Header params – simple example from our JCG partner Paris Apostolopoulos at the Papo’s log blog. |