java - multiple - spring security preauthorize
¿Puede Spring Security usar @PreAuthorize en los métodos de los controladores Spring? (6)
Han pasado más de dos años desde que se hizo esta pregunta pero, debido a los problemas que tuve hoy, preferiría desalentar el uso de @Secured
, @PreAuthorize
, etc. en @Controller
s.
Lo que no funcionó para mí fue @Validated
combinado con el controlador @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) {
// ...
}
El validador simplemente no se activa (Spring MVC 4.1.2, Spring Security 3.2.5) y no se realizan comprobaciones.
Problemas similares son causados por los proxys CGLIB utilizados por Spring (cuando no hay una interfaz implementada por una clase, Spring crea el proxy CGLIB, si la clase implementa cualquier interfaz se genera JDK Proxy - documentation , bien explicada aquí y here ).
Como mencioné en las respuestas que he vinculado anteriormente, no es mejor usar las anotaciones de Spring Security en la capa de servicio que generalmente implementa interfaces (por lo que se utilizan los Proxy JDK) ya que esto no genera tales problemas.
Si desea proteger los controladores web, la mejor idea es usar <http>
y <intercept-url />
que están vinculados a direcciones URL específicas en lugar de a métodos en controladores y funcionan bastante bien. En mi caso:
<http use-expressions="true" disable-url-rewriting="true">
...
<intercept-url pattern="/administration/**" access="hasRole(''ROLE_ADMIN'')" />
</http>
¿Puede Spring Security usar @PreAuthorize
en los métodos de los controladores Spring?
Para extender la respuesta proporcionada por Andy, puede usar:
@PreAuthorize("hasRole(''foo'')")
para verificar el rol específico.
Sí, funciona bien.
Necesita <security:global-method-security pre-post-annotations="enabled" />
in ...-servlet.xml
. También requiere proxies CGLIB , por lo tanto, sus controladores no deberían tener interfaces, o debería usar proxy-target-class = true
.
Si está utilizando Spring 3.1, puede hacer algunas cosas muy interesantes con esto. Eche un vistazo a https://github.com/mohchi/spring-security-request-mapping . Es un proyecto de muestra que integra @PreAuthorize con RequestMappingHandlerMapping de Spring MVC para que pueda hacer algo como:
@RequestMapping("/")
@PreAuthorize("isAuthenticated()")
public String authenticatedHomePage() {
return "authenticatedHomePage";
}
@RequestMapping("/")
public String homePage() {
return "homePage";
}
Una solicitud de "/" llamará a authenticatedHomePage () si el usuario está autenticado. De lo contrario, llamará homePage ().
Ver las preguntas frecuentes de Spring Security (énfasis mío).
En una aplicación web de Spring, el contexto de la aplicación que contiene los beans de Spring MVC para el servlet del despachador a menudo está separado del contexto de la aplicación principal. A menudo se define en un archivo llamado myapp-servlet.xml, donde "myapp" es el nombre asignado al Spring DispatcherServlet en web.xml. Una aplicación puede tener múltiples DispatcherServlets, cada uno con su propio contexto de aplicación aislado. Los beans en estos contextos "secundarios" no son visibles para el resto de la aplicación. El ContextLoaderListener que usted define en su web.xml carga el contexto de la aplicación "principal" y es visible para todos los contextos secundarios. Este contexto principal generalmente es donde define su configuración de seguridad, incluido el elemento). Como resultado, no se aplicarán las restricciones de seguridad aplicadas a los métodos en estos beans web, ya que los beans no se pueden ver desde el contexto DispatcherServlet. Debe mover la declaración al contexto web o mover los beans que desea asegurar al contexto principal de la aplicación.
En general, recomendaríamos aplicar la seguridad del método en la capa de servicio en lugar de en los controladores web individuales.
Si aplica puntos de corte a la capa de servicio, solo necesita establecer <global-method-security>
en el contexto de seguridad de su aplicación.
Ya hay una respuesta sobre cómo hacer que funcione cambiando la configuración xml; sin embargo, si está trabajando con una configuración basada en código, puede lograr lo mismo colocando la siguiente anotación sobre su clase @Configuration
:
@EnableGlobalMethodSecurity(prePostEnabled=true)