Статьи

CDI-перехватчик параметров HTTP Request и Header — простой пример

При разработке и развитии REST API с использованием Java EE в некоторых случаях вы хотели бы «взглянуть» на входящий HTTP-запрос, в частности на параметры заголовка , более детально (для каждого случая), чем фильтр сервлетов или более конкретные ContainerRequestFilters .

Один из возможных способов, который я нахожу в некоторых случаях очень удобным, — это добавление перехватчиков CDI в мою реализацию JAXRS Resource , которые в конечном итоге получают доступ к входящему HTTP-запросу и выполняют некоторую «пользовательскую» логику. Как разработчик, я могу полностью контролировать — где (в каких путях) перехватывать запрос, просто добавляя или удаляя пользовательскую аннотацию. С введением Java EE 7 легче смешивать «проблемы», поэтому вы можете легко внедрить HTTP-запрос к обычным перехватчикам CDI .

Ниже я просто документирую очень простой пример, в котором я использую пользовательский перехватчик для «перехвата» HTTP-запросов в бизнес-REST API, чтобы выполнить очень специфическую пользовательскую логику аутентификации. Я проверяю, находится ли «пользователь», инициирующий запрос в моем REST API, в какой-то определенной пользовательской роли, которую определяет моя система. Конечно, общий пример — всего лишь пример, но вы поняли идею.

Чтобы внедрить такой компонент, вам нужно 2 вещи:

  • ввести пользовательскую аннотацию, которая будет использоваться для активации перехватчика, когда он определен
  • реализовать перехватчик CDI.
  • применить аннотацию, на пути / ресурсы вашего отдыха API

Интерфейс аннотации

Здесь нет ничего необычного, только пользовательская аннотация во время выполнения, поэтому мы можем использовать ее для «маркировки» определенных методов нашего JAXRS API.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
package gr.javapapo.sample.cdi;
 
/**
 * Created by <a href="mailto:[email protected]">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";
}

Реализация перехватчика

Интересные моменты:

  • перехватчик «помечен» нашей пользовательской аннотацией — просто
  • мы @ Внедрим HttpServletReqest
  • Мы применяем некоторую пользовательскую логику, основанную на деталях аннотации (я читаю любые параметры определения)
  • Из запроса я прочитал заголовок и на основе параметров аннотации — я делаю некоторые основные логики
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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:[email protected]">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();
    }
}

Применение перехватчика / аннотации

В конце концов, вы можете просто аннотировать свои ресурсы и методы @Path JAXRS, чтобы «вставить» свою собственную логику:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
@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();
    }