Может ли 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).