Enterprise Java

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();
    }

Paris Apostolopoulos

Paris is a senior software engineer focusing on J2EE development, loves Business process modelling and is keen on software quality challenges. He is passionate about Java and Java communities. He is a co-founder and administrator of the first Java User Group in greece(JHUG.gr) and occasional speaker on meet-ups and seminars and regular blogger. For his contributions and involvement on the Java community he has been awarded the title of Java Champion in 2007 by Sun Microsystems.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button