Может ли Spring использовать безопасность @PreAuthorize
в Spring методах контроллеров?
Может ли Spring использовать безопасность @PreAuthorize в методах контроллеров Spring?
Ответ 1
Да, он отлично работает.
Вам нужно <security:global-method-security pre-post-annotations="enabled" />
в ...-servlet.xml
. Он также требует прокси CGLIB, поэтому либо ваши контроллеры не должны иметь интерфейсов, либо использовать proxy-target-class = true
.
Ответ 2
См. Spring FAQ по безопасности (выделение мое).
В веб-приложении Spring контекст приложения, который содержит Spring MVC beans для сервлета диспетчера часто отделяется от основной контекст приложения. Он часто определяется в файле с именем myapp-servlet.xml, где "myapp" - это имя, присвоенное SpringDispatcherServlet в web.xml. Приложение может иметь несколько DispatcherServlets, каждый со своим изолированным контекстом приложения. beans в этих "дочерних" контекстах не видны остальным выражение. Контекст "родительского" приложения загружается ContextLoaderListener, который вы определяете в своем web.xml и видим для всех детского контекста. Этот родительский контекст обычно используется там, где вы определяете вашей конфигурации безопасности, включая элемент). В результате любые ограничения безопасности, применяемые к методам в эти веб-страницы beans не будут применяться, поскольку beans не может быть замечен из контекста DispatcherServlet. Вам нужно либо переместить объявления в веб-контекст или beans, который вы хотите зафиксировать в главном контексте приложения.
Обычно мы рекомендуем применять метод безопасности на службе а не на отдельных веб-контроллерах.
Если вы применяете pointcuts к уровню обслуживания, вам нужно установить <global-method-security>
в контекст безопасности приложения.
Ответ 3
Если вы используете Spring 3.1, вы можете сделать довольно классный материал с этим. Посмотрите https://github.com/mohchi/spring-security-request-mapping. Это пример проекта, который объединяет @PreAuthorize с Spring MVC RequestMappingHandlerMapping, чтобы вы могли сделать что-то вроде:
@RequestMapping("/")
@PreAuthorize("isAuthenticated()")
public String authenticatedHomePage() {
return "authenticatedHomePage";
}
@RequestMapping("/")
public String homePage() {
return "homePage";
}
Запрос на "/" вызывает аутентификациюHomePage(), если пользователь аутентифицирован. В противном случае он вызовет homePage().
Ответ 4
В течение двух лет с тех пор, как был задан этот вопрос, но из-за проблем, с которыми я столкнулся сегодня, я бы предпочел отказаться от использования @Secured
, @PreAuthorize
и т.д. на @Controller
s.
Для меня не было @Validated
в сочетании с контроллером @Secured
:
@Controller
@Secured("ROLE_ADMIN")
public class AdministrationController {
// @InitBinder here...
@RequestMapping(value = "/administration/add-product", method = RequestMethod.POST)
public String addProductPost(@ModelAttribute("product") @Validated ProductDto product, BindingResult bindingResult) {
// ...
}
Валидатор просто не запускает (Spring MVC 4.1.2, Spring Security 3.2.5) и никаких проверок не выполняется.
Подобные проблемы вызваны проксими CGLIB, используемыми Spring (при отсутствии интерфейса, реализованного классом, Spring создает прокси CGLIB; если класс реализует какой-либо интерфейс, тогда создается JDK-прокси - документация, хорошо объяснено здесь и здесь).
Как уже упоминалось в ответах, которые были связаны выше, лучше использовать Spring аннотации безопасности на уровне обслуживания, которые обычно реализуют интерфейсы (поэтому используются JDK-прокси), поскольку это не приводит к таким проблемам.
Если вы хотите защитить веб-контроллеры, лучше использовать <http>
и <intercept-url />
, которые привязаны к определенным URL-адресам, а не методы в контроллерах и работают очень хорошо. В моем случае:
<http use-expressions="true" disable-url-rewriting="true">
...
<intercept-url pattern="/administration/**" access="hasRole('ROLE_ADMIN')" />
</http>
Ответ 5
Чтобы продлить ответ, предоставленный Энди, вы можете использовать:
@PreAuthorize("hasRole('foo')")
чтобы проверить конкретную роль.
Ответ 6
Уже есть ответ о том, как заставить его работать, изменяя конфигурацию xml, однако, если вы работаете с конфигурацией на основе кода, вы можете добиться того же, поставив перед собой следующую аннотацию @Configuration
class: @EnableGlobalMethodSecurity(prePostEnabled=true)
.