Preámbulo: desde Spring-Security 3.2 hay una buena anotación @AuthenticationPrincipal
descrita al final de esta respuesta. Esta es la mejor manera de usar Spring-Security> = 3.2.
Cuando usted:
- use una versión anterior de Spring-Security,
- necesita cargar su objeto de usuario personalizado de la base de datos mediante alguna información (como el inicio de sesión o la identificación) almacenada en el principal o
- desee aprender una
HandlerMethodArgumentResolver
o WebArgumentResolver
puede solucionar esto de una manera elegante, o simplemente quieren aprender un segundo plano detrás @AuthenticationPrincipal
y AuthenticationPrincipalArgumentResolver
(debido a que se basa en una HandlerMethodArgumentResolver
)
luego siga leyendo; de lo contrario, solo use @AuthenticationPrincipal
y agradezca a Rob Winch (Autor de @AuthenticationPrincipal
) y Lukas Schmelzeisen (por su respuesta).
(Por cierto: mi respuesta es un poco más antigua (enero de 2012), por lo que fue Lukas Schmelzeisen quien surgió como el primero con la @AuthenticationPrincipal
solución de anotación basada en Spring Security 3.2.)
Entonces puedes usar en tu controlador
public ModelAndView someRequestHandler(Principal principal) {
User activeUser = (User) ((Authentication) principal).getPrincipal();
...
}
Eso está bien si lo necesitas una vez. Pero si lo necesita varias veces es feo porque contamina su controlador con detalles de infraestructura, eso normalmente debería estar oculto por el marco.
Entonces, lo que realmente puede desear es tener un controlador como este:
public ModelAndView someRequestHandler(@ActiveUser User activeUser) {
...
}
Por lo tanto, solo necesita implementar a WebArgumentResolver
. Tiene un metodo
Object resolveArgument(MethodParameter methodParameter,
NativeWebRequest webRequest)
throws Exception
Eso obtiene la solicitud web (segundo parámetro) y debe devolver el User
si se siente responsable del argumento del método (el primer parámetro).
Desde la primavera 3.1 hay un nuevo concepto llamado HandlerMethodArgumentResolver
. Si usa Spring 3.1+, entonces debe usarlo. (Se describe en la siguiente sección de esta respuesta))
public class CurrentUserWebArgumentResolver implements WebArgumentResolver{
Object resolveArgument(MethodParameter methodParameter, NativeWebRequest webRequest) {
if(methodParameter is for type User && methodParameter is annotated with @ActiveUser) {
Principal principal = webRequest.getUserPrincipal();
return (User) ((Authentication) principal).getPrincipal();
} else {
return WebArgumentResolver.UNRESOLVED;
}
}
}
Debe definir la anotación personalizada: puede omitirla si cada instancia de usuario siempre debe tomarse del contexto de seguridad, pero nunca es un objeto de comando.
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ActiveUser {}
En la configuración solo necesita agregar esto:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"
id="applicationConversionService">
<property name="customArgumentResolver">
<bean class="CurrentUserWebArgumentResolver"/>
</property>
</bean>
@Ver: aprenda a personalizar los argumentos del método Spring MVC @Controller
Cabe señalar que si está utilizando Spring 3.1, recomiendan HandlerMethodArgumentResolver sobre WebArgumentResolver. - ver comentario de Jay
Lo mismo con HandlerMethodArgumentResolver
Spring 3.1+
public class CurrentUserHandlerMethodArgumentResolver
implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
return
methodParameter.getParameterAnnotation(ActiveUser.class) != null
&& methodParameter.getParameterType().equals(User.class);
}
@Override
public Object resolveArgument(MethodParameter methodParameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
if (this.supportsParameter(methodParameter)) {
Principal principal = webRequest.getUserPrincipal();
return (User) ((Authentication) principal).getPrincipal();
} else {
return WebArgumentResolver.UNRESOLVED;
}
}
}
En la configuración, debe agregar esto
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="CurrentUserHandlerMethodArgumentResolver"/>
</mvc:argument-resolvers>
</mvc:annotation-driven>
@Ver Aprovechar la interfaz Spring MVC 3.1 HandlerMethodArgumentResolver
Solución Spring-Security 3.2
Spring Security 3.2 (no confundir con Spring 3.2) tiene su propia solución integrada: @AuthenticationPrincipal
( org.springframework.security.web.bind.annotation.AuthenticationPrincipal
). Esto se describe muy bien en la respuesta de Lukas Schmelzeisen
Es solo escribir
ModelAndView someRequestHandler(@AuthenticationPrincipal User activeUser) {
...
}
Para que esto funcione, debe registrar el AuthenticationPrincipalArgumentResolver
( org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver
): ya sea "activando" @EnableWebMvcSecurity
o registrando este bean dentro mvc:argument-resolvers
, de la misma manera que lo describí con la solución Spring 3.1 anterior.
@ Consulte Spring Security 3.2 Reference, Capítulo 11.2. @AuthenticationPrincipal
Solución Spring-Security 4.0
Funciona como la solución Spring 3.2, pero en Spring 4.0 el @AuthenticationPrincipal
y AuthenticationPrincipalArgumentResolver
fue "movido" a otro paquete:
(Pero las clases antiguas en sus paquetes anteriores todavía existen, ¡así que no las mezcle!)
Es solo escribir
import org.springframework.security.core.annotation.AuthenticationPrincipal;
ModelAndView someRequestHandler(@AuthenticationPrincipal User activeUser) {
...
}
Para que esto funcione, debe registrar el ( org.springframework.security.web.method.annotation.
) AuthenticationPrincipalArgumentResolver
: ya sea "activando" @EnableWebMvcSecurity
o registrando este bean dentro mvc:argument-resolvers
, de la misma manera que lo describí con la solución Spring 3.1 anterior.
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver" />
</mvc:argument-resolvers>
</mvc:annotation-driven>
@ Consulte Spring Security 5.0 Reference, Capítulo 39.3 @AuthenticationPrincipal
(id="applicationConversionService")
en el ejemploSi bien Ralphs Answer ofrece una solución elegante, con Spring Security 3.2 ya no necesita implementar la suya
ArgumentResolver
.Si tiene una
UserDetails
implementaciónCustomUser
, simplemente puede hacer esto:Consulte la documentación de seguridad de Spring: @AuthenticationPrincipal
fuente
@EnableWebMvcSecurity
XML o en XML:<mvc:annotation-driven> <mvc:argument-resolvers> <bean class="org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver" /> </mvc:argument-resolvers> </mvc:annotation-driven>
customUser
es nulo o no?if (customUser != null) { ... }
Spring Security está diseñado para funcionar con otros frameworks que no sean Spring, por lo tanto, no está estrechamente integrado con Spring MVC. Spring Security devuelve el
Authentication
objeto delHttpServletRequest.getUserPrincipal()
método por defecto, así que eso es lo que obtienes como principal. Puede obtener suUserDetails
objeto directamente de esto usandoTenga en cuenta también que los tipos de objeto pueden variar según el mecanismo de autenticación utilizado (puede que no obtenga un
UsernamePasswordAuthenticationToken
, por ejemplo) y elAuthentication
estrictamente no tiene que contener unUserDetails
. Puede ser una cadena o cualquier otro tipo.Si no desea llamar
SecurityContextHolder
directamente, el enfoque más elegante (que seguiría) es inyectar su propia interfaz de acceso al contexto de seguridad personalizada que se personaliza para satisfacer sus necesidades y tipos de objetos de usuario. Cree una interfaz, con los métodos relevantes, por ejemplo:Luego puede implementar esto accediendo a
SecurityContextHolder
en su implementación estándar, desacoplando por completo su código de Spring Security. Luego inyecte esto en los controladores que necesitan acceso a información de seguridad o información sobre el usuario actual.El otro beneficio principal es que es fácil realizar implementaciones simples con datos fijos para la prueba, sin tener que preocuparse por poblar locales de subprocesos, etc.
fuente
Implemente la
HandlerInterceptor
interfaz y luego inyecteUserDetails
en cada solicitud que tenga un Modelo, de la siguiente manera:fuente
<mvc:interceptors>
archivo de configuración de mi aplicación.spring-security-taglibs
: stackoverflow.com/a/44373331/548473A partir de Spring Security versión 3.2, la funcionalidad personalizada que ha sido implementada por algunas de las respuestas anteriores existe de forma inmediata en forma de
@AuthenticationPrincipal
anotación respaldada porAuthenticationPrincipalArgumentResolver
.Un ejemplo simple de su uso es:
CustomUser debe ser asignable desde
authentication.getPrincipal()
Aquí están los correspondientes Javadocs de AuthenticationPrincipal y AuthenticationPrincipalArgumentResolver
fuente
fuente
Y si necesita un usuario autorizado en plantillas (por ejemplo, JSP) use
Juntos con
fuente
Puede intentar esto: Al usar el Objeto de autenticación de Spring podemos obtener detalles del usuario en el método del controlador. A continuación se muestra el ejemplo, pasando el objeto de autenticación en el método del controlador junto con el argumento. Una vez que el usuario se autentica, los detalles se rellenan en el objeto de autenticación.
fuente