Как проверить, содержится ли неподдерживаемый параметр в запросе REST? - PullRequest
0 голосов
/ 16 декабря 2018

Есть ли у Spring (boot) способ проверить, содержит ли запрос REST параметр, явно не объявленный вызываемым методом REST?

С помощью флага required мы можем принудительно установитьклиент для включения определенного параметра в запрос.Я ищу аналогичный способ запретить клиенту отправлять параметр, который не является явным, упомянутым в объявлении метода контроллера:

@RequestMapping("/hello")
public String hello(@RequestParam(value = "name") String name) {
    //throw an exception if a REST client calls this method and 
    //  sends a parameter with a name other than "name"
    //otherwise run this method's logic
}

Например, вызов

curl "localhost:8080/hello?name=world&city=London"

долженрезультат в ответе 4xx .

Одним из вариантов будет явная проверка на неожиданные параметры:

@RequestMapping("/hello")
public String hello(@RequestParam Map<String,String> allRequestParams) {
    //throw an exception if allRequestParams contains a key that we cannot process here
    //otherwise run this method's logic
}

Но возможно ли достичь того же результата при сохранениитакое же удобное @RequestParam использование, как в первом примере?

EDIT : Извините, я не вижу никакой связи с этим вопросом .Другой вопрос касается обработки аннотаций во время выполнения.Мой вопрос касается поведения REST-движка Spring.Я что-то упустил?

РЕДАКТИРОВАТЬ : На основе ответов я написал это HandlerInterceptor :

@Component
public class TooManyParamatersHandlerInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        HandlerMethod m = (HandlerMethod) handler;
        if (m.getMethod().getName().equals("error")) {
            return true;
        }
        List<String> allowedParameters = Stream.of(m.getMethodParameters())
                .flatMap(p -> Stream.of(p.getParameterAnnotation(RequestParam.class)))
                .filter(Objects::nonNull)
                .map(RequestParam::name).collect(Collectors.toList());
        ArrayList<String> actualParameters = Collections.list(request.getParameterNames());
        actualParameters.removeAll(allowedParameters);
        if (!actualParameters.isEmpty()) {
            throw new org.springframework.web.bind.ServletRequestBindingException(
                "unexpected parameter: " + actualParameters);
        }
        return true;
    }
}

Ответы [ 3 ]

0 голосов
/ 16 декабря 2018

В этом случае требуется HandlerInterceptor или HandlerInterceptorAdapter, переопределить метод preHandle

@Override
public boolean preHandle(HttpServletRequest request,
        HttpServletResponse response, Object handler) throws Exception {
           //request param validation validation
            return true; //or throw exception 
}

ServletRequest.getParameterMap () возвращает карту значений ключей параметров запроса.

0 голосов
/ 17 декабря 2018

Насколько я знаю, вы не можете просто запретить параметры с помощью Spring.Честно говоря, этот вопрос довольно сомнительный и ненужный, и я думаю, что это антипаттерн.

Однако Spring предоставляет при каждом сопоставлении объектов HttpServletRequest и HttpServletResponse сигнатуру метода контроллера.Используйте метод HttpServletRequest::getParameterMap, чтобы получить карту переданных параметров для дальнейшей итерации и проверки.

@RequestMapping("/hello")
public String hello(RequestParam(value = "name") String name, HttpServletRequest request, HttpServletResponse response) {
    final Map<String, String[]> parameterMap = request.getParameterMap();
    // logics
}

Передача этих объектов только в @RequestMapping("/hello") позволяет выполнить проверкутолько для выбранного отображения.Если вы хотите определить это поведение глобально, я предлагаю вам использовать HandlerInterceptor::preHandle, как здесь ответили.

Если вы зададите параметр hello required=true,тогда вы можете просто проверить размер карты, равный 1 или нет.

0 голосов
/ 16 декабря 2018

Вы можете сделать это с помощью функции ContainerRequestFilter, добавленной из JavaEE 7, которая позволяет получить доступ к классу ресурса и методу ресурса, совпадающему с текущим запросом, и заставить вас выполнить действие по желанию, если оно не было сопоставлено.

Вы можете прочитать больше здесь:

https://docs.oracle.com/javaee/7/api/javax/ws/rs/container/ResourceInfo.html

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;

import javax.ws.rs.QueryParam;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.Provider;

@Provider
public class RequestParamFilter implements ContainerRequestFilter {

    @Context
    private ResourceInfo resourceInfo;

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        Set<String> acceptedParamList = new HashSet<String>();
        Method method = resourceInfo.getResourceMethod();
        for (Annotation[] annos : method.getParameterAnnotations()) {
            for (Annotation anno : annos) {
                if (anno instanceof QueryParam) {
                    acceptedParamList.add(((QueryParam) anno).value());
                }
            }
        }

        MultivaluedMap<String, String> queryParams = requestContext.getUriInfo().getQueryParameters();
        for (String param : queryParams .keySet()) {
            if (!acceptedParamList.contains(param)) {
                requestContext.abortWith(Response.status(Status.BAD_REQUEST).entity("Unexpected paramter found : "+param).build());
            }
        }
    }

}

PN: Фильтры в большинстве случаев стоят на скорости вашего приложения, особенно если у вас сложныецепочки в нем!

Я рекомендую использовать его в этом случае (и аналогичных случаях), так как большинство этих запросов вообще не должны поступать на серверное приложение.

Я надеюсь, что это поможет вам и счастливого кодирования!=) * * 1016

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...