Spring Data JPA Недопустимые параметры page.sort

В веб-приложении, которое использует Spring Data JPA с Hibernate, мы используем веб-пагинация для обеспечения возможности разбиения по страницам и сортировки в различных списках объектов.

@Controller
public class MyEntityController {
   @RequestMapping(method = RequestMethod.GET)
   public ModelAndView list(Pageable pageable) { ... }
}

@Configuration
public class MyWebMvcConfig extends WebMvcConfigurationSupport {
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        super.addArgumentResolvers(argumentResolvers);
        argumentResolvers.add(new PageableArgumentResolver());
    }
}

public interface MyEntityRepository extends PagingAndSortingRepository<MyEntity, String> {
    Page<MyEntity> findByPropertyX(String propertyX, Pageable pagable);
}

Это позволяет определять свойства объекта в визуализированном HTML как специальную сортировку параметры запроса, где значение page.sort фактически соответствует свойству объекта, по которому выполняется сортировка.

<table>
    <thead>
        <tr>
            <th><a href="?page.sort=propertyX&amp;page.sort.dir=asc">Property X</a></th>
            <th><a href="?page.sort=propertyY&amp;page.sort.dir=asc">Property Y</a></th>
        </tr>
    </thead>
    <tbody>...</tbody>
</table>

В результате будет получен URL-адрес, например:

http://host/context-root/entities/?page.sort=propertyX&page.sort.dir=asc

Проблема в том, что пользователи могут изменить URL-адрес, чтобы использовать недопустимые свойства page.sort, которые либо ссылаются на несуществующие имена столбцов / свойств, либо, что еще хуже, используют недопустимые символы запроса JPA, что приводит к недопустимому синтаксису.

Например, если URL-адрес изменен для сортировки по «noSuchProperty»:

http://host/context-root/entities/?page.sort=noSuchProperty&page.sort.dir=asc

Но этого свойства не существует, будет выдано следующее исключение:

java.lang.IllegalArgumentException: No property noSuchProperty found for type class com.my.company.MyEntity
    at org.springframework.data.repository.query.parser.Property.<init>(Property.java:76)
     . . .
    at org.springframework.data.repository.query.parser.AbstractQueryCreator.createQuery(AbstractQueryCreator.java:86)
     . . .
    at $Proxy68.findByPropertyX(Unknown Source)
    at com.my.company.MyEntityRepository.findByPropertyX(MyEntityRepository.java:17

Аналогичным образом, если URL-адрес изменен на недопустимый символ синтаксиса запроса, например "" ":

http://host/context-root/entities/?page.sort=%22&page.sort.dir=asc

Произойдет следующая ошибка:

java.lang.StackOverflowError
    java.util.regex.Pattern$GroupTail.match(Pattern.java:4227)
    . . .
    org.springframework.data.repository.query.parser.Property.create(Property.java:326)
    org.springframework.data.repository.query.parser.Property.create(Property.java:326)
    org.springframework.data.repository.query.parser.Property.create(Property.java:326)
    org.springframework.data.repository.query.parser.Property.create(Property.java:326)

(Существует также третий вариант исключений, который приводит к org.hibernate.QueryException, когда @Query явно определен в методе репозитория.)

Spring Data JPA абстрагирует детали сортировки, разбиения по страницам и обработки этих параметров; однако, похоже, что он не может корректно обрабатывать эти сценарии (т.е. когда указан недопустимый параметр сортировки).

Мы могли бы добавить некоторую дополнительную настраиваемую логику для проверки того, что свойство сортировки действительно существует в сущности; однако мне интересно, есть ли более чистый и централизованный подход для этого, чтобы мы не теряли преимущества и простоту абстракций Spring Data JPA. Мы используем эту возможность сортировки во всем нашем приложении с множеством различных сущностей, поэтому в идеале нам нужен более общий подход, а не необходимость явно определять или проверять свойства сортировки для каждой запрошенной страницы сущности.

В частности, мы фактически расширяем PageableArgumentResolver, чтобы принять аннотированное значение сортировки по умолчанию, которое предоставляется в нашем контроллере (не показано в примерах кода для простоты), поэтому мы хотели бы просто вернуться к этому порядку сортировки по умолчанию или просто к сортировке по умолчанию порядок для объекта, а не выбросить исключение.

Некоторые идеи и попытки ... Я мог бы использовать QueryCreationListener, чтобы перехватить создание запроса и получить параметр сортировки; однако на данный момент я не могу изменить запрос. Или я могу расширить и использовать пользовательский PageableArgumentResolver (мы уже делаем это), чтобы получить параметры сортировки; однако в этот момент у меня нет доступа к объекту или возможности определить, действительно ли объект имеет свойство с таким именем. Мы могли бы явно объявить поддерживаемые свойства; однако, опять же, это подрывает идею централизованной и автоматической обработки этого сценария, не требуя конкретных или заявленных знаний об объектах.

Есть ли какой-либо другой тип перехватчика или аналогичная конструкция, которую я могу использовать для централизованной проверки параметров сортировки на странице и изменения, если необходимо, перед вызовом запроса? Или есть какой-либо тип конфигурации или способ, которым Spring может автоматически обрабатывать этот сценарий, чтобы он более изящно обрабатывал недопустимые параметры сортировки?


person shelley    schedule 27.06.2012    source источник


Ответы (2)


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

Здесь есть два сценария, в первом вы передаете поле сортировки, которого нет в объекте / таблице. На самом деле вам нужно, чтобы этот плохой параметр постоянно игнорировался, а не только при передаче 1_1 _] 1. Я думаю, это должен быть вариант на _ 2_ (и, следовательно, _ 3_), чтобы игнорировать неверные параметры при сортировке.

Вторая часть, которую следует решить, - это, вероятно, _ 4_. Если вы передаете пустые строки или что-то, что не имеет смысла, например %20, он должен игнорировать этот параметр и не отправлять его в PageRequest.

Удачного взлома и удачи. Прочитав ваш пост, я понял, что мой сайт уязвим для той же проблемы, и у меня действительно нет хорошего решения.

person sbzoom    schedule 16.10.2012

Я думаю, что улучшение PageableArgumentResolver, чтобы изящно справляться с этими сценариями. Он может попытаться создать PropertyPath экземпляр из String, переданного как Sort, и таким образом убедиться, что он действительный. Я немного раздумываю, имеет ли смысл просто отбрасывать недействительный String по умолчанию, который вернет результат, который вообще не будет отсортирован. Это, вероятно, самый простой способ, но он также может привести к утомительным попыткам выяснить, почему результат не отсортирован.

Однако это. Было бы здорово, если бы вы могли поднять билет JIRA для этого против Spring Data Commons и просто привязать этот билет здесь. Не стесняйтесь открывать пул-реквест, если у вас есть жизнеспособная реализация. Спасибо, что уже подали это на стол!

person Oliver Drotbohm    schedule 28.06.2012