В веб-приложении используется Spring WebMVC и Spring Security. Возник вопрос, почему не работает аннотация @PreAuthorize, если повесить её на вложенный метод в классе контроллера:
@GetMapping(value= "/method")
public String exampleForMethodPreAuthorize() {
if(methodController()){
return "forMethodPreAuthorize";
}
else return null;
}
@PreAuthorize("hasRole('ADMIN')")
public final boolean methodController(){
return true;
}
Код выше не работает, т.е. метод срабатывает для любых пользователей, даже тех, кто не имеет полномочий доступа Admin. Хотя, если эту аннотацию расположить на самом методе контроллера:
@PreAuthorize("hasRole('ADMIN')")
@GetMapping(value= "/method")
public String exampleForMethodPreAuthorize() {
return "forMethodPreAuthorize";
}
то в этом случае всё работает отлично. Естественно, в файле конфигурации сервлет-контекста используется component-scan и
<security:global-method-security pre-post-annotations="enabled"/>
Заранее спасибо за ответ.
Пожалуй, разверну оба варианта своего ответа, так как, может быть не в этом конкретном случае, но надо учитывать все возможные причины такого поведения.
Во-первых, Spring заворачивает бин контроллера в прокси-объект, перехватывающий все вызовы к методам и проверяющий соответствие прав доступа выражению в аннотации @PreAuthorize
. Но прокси-объект не может перехватывать вызовы внутри целевого объекта, только вызовы извне. С этим можно столкнулся при использовании многих аннотаций, не только аннотаций Spring Security.
Во-вторых, в приложениях использующих Spring Security, до того как попасть в dispatcher servlet и после к контроллеру, запрос проходит через цепочку сервлетных фильтров.
В частности, через FilterSecurityInterceptor, который как раз проверяет истинность security expressions и отбрасывает запрос ещё до того, как контроллер получит управление, если выражение ложно.
Поэтому я удивлён, честно говоря, что Spring Security делает ещё одну проверку при вызове метода.
Sergey, ваш первый ответ натолкнул меня на мысль, благодаря чему я нашёл ответ на свой вопрос. Действительно, бин контроллера проксируется и видимо из-за этого внутренние вызовы методов не проверяются на аннотацию @PreAuthorize. Потребовалось в отдельном классе, аннотированном @Component, создать метод, который предназначен вызываться из метода контроллера и инжектировать бин данного класса в класс контроллера при помощи @Autowired. Дело в том, что механизм использования аннотации @PreAuthorize сам основан на создании прокси для бина соответствующего класса и проверкой этим прокси вызовов методов на наличие данной аннотации. Поэтому метод с аннотацией @PreAuthorize должен быть в классе-бине. Примерно так:
@Controller
public class MvcController {
@Autowired
SomeClass someClass;
@GetMapping(value= "/externalMethod")
public String exampleForExternalMethodPreAuthorize() {
if(someClass.externalMethod()){
return "forMethodPreAuthorize";
}
else return null;
}
}
@Component
public class SomeClass {
@PreAuthorize("hasRole('ADMIN')")
public boolean externalMethod() {
return true;
}
}
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
В моем проекте необходима база данных SQLite, с которой я буду работать через HibernateРаботаю в Net Beans, ОС Ubuntu 17
Необходим бесплатный хостинг для апробации сервера на JavaТак же необходима поддержка SQLite или другой БД