Préambule: Depuis Spring-Security 3.2, il y a une belle annotation @AuthenticationPrincipal
décrite à la fin de cette réponse. C'est la meilleure façon de procéder lorsque vous utilisez Spring-Security> = 3.2.
Lorsque vous:
- utiliser une ancienne version de Spring-Security,
- besoin de charger votre objet utilisateur personnalisé à partir de la base de données par certaines informations (comme le login ou l'id) stockées dans le principal ou
- voulez apprendre comment a
HandlerMethodArgumentResolver
ou WebArgumentResolver
peut résoudre cela de manière élégante, ou voulez simplement apprendre le contexte derrière @AuthenticationPrincipal
et AuthenticationPrincipalArgumentResolver
(parce qu'il est basé sur a HandlerMethodArgumentResolver
)
puis continuez à lire - sinon utilisez simplement @AuthenticationPrincipal
et merci à Rob Winch (auteur de @AuthenticationPrincipal
) et Lukas Schmelzeisen (pour sa réponse).
(BTW: Ma réponse est un peu plus ancienne (janvier 2012), c'est donc Lukas Schmelzeisen qui est apparu comme le premier avec la @AuthenticationPrincipal
solution d'annotation basée sur Spring Security 3.2.)
Ensuite, vous pouvez utiliser dans votre contrôleur
public ModelAndView someRequestHandler(Principal principal) {
User activeUser = (User) ((Authentication) principal).getPrincipal();
...
}
Ce n'est pas grave si vous en avez besoin une fois. Mais si vous en avez besoin plusieurs fois, c'est moche car il pollue votre contrôleur avec des détails d'infrastructure, cela devrait normalement être caché par le framework.
Donc, ce que vous voudrez peut-être vraiment, c'est avoir un contrôleur comme celui-ci:
public ModelAndView someRequestHandler(@ActiveUser User activeUser) {
...
}
Par conséquent, il vous suffit de mettre en œuvre un WebArgumentResolver
. Il a une méthode
Object resolveArgument(MethodParameter methodParameter,
NativeWebRequest webRequest)
throws Exception
Cela obtient la requête Web (deuxième paramètre) et doit renvoyer le User
s'il se sent responsable de l'argument de la méthode (le premier paramètre).
Depuis le printemps 3.1, il existe un nouveau concept appelé HandlerMethodArgumentResolver
. Si vous utilisez Spring 3.1+, vous devez l'utiliser. (Il est décrit dans la section suivante de cette réponse))
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;
}
}
}
Vous devez définir l'annotation personnalisée - Vous pouvez l'ignorer si chaque instance de User doit toujours être extraite du contexte de sécurité, mais n'est jamais un objet de commande.
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ActiveUser {}
Dans la configuration, il vous suffit d'ajouter ceci:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"
id="applicationConversionService">
<property name="customArgumentResolver">
<bean class="CurrentUserWebArgumentResolver"/>
</property>
</bean>
@See: Apprenez à personnaliser les arguments de la méthode Spring MVC @Controller
Il convient de noter que si vous utilisez Spring 3.1, ils recommandent HandlerMethodArgumentResolver sur WebArgumentResolver. - voir le commentaire de Jay
La même chose avec HandlerMethodArgumentResolver
pour 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;
}
}
}
Dans la configuration, vous devez ajouter ceci
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="CurrentUserHandlerMethodArgumentResolver"/>
</mvc:argument-resolvers>
</mvc:annotation-driven>
@Voir Utilisation de l'interface Spring MVC 3.1 HandlerMethodArgumentResolver
Solution Spring-Security 3.2
Spring Security 3.2 (ne pas confondre avec Spring 3.2) a sa propre solution intégrée: @AuthenticationPrincipal
(org.springframework.security.web.bind.annotation.AuthenticationPrincipal
). Ceci est bien décrit dans la réponse de Lukas Schmelzeisen
C'est juste écrire
ModelAndView someRequestHandler(@AuthenticationPrincipal User activeUser) {
...
}
Pour que cela fonctionne, vous devez enregistrer le AuthenticationPrincipalArgumentResolver
( org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver
): soit en "activant" @EnableWebMvcSecurity
soit en enregistrant ce bean dans mvc:argument-resolvers
- de la même manière que je l'ai décrit avec la solution Spring 3.1 ci-dessus.
@ Voir Spring Security 3.2 Reference, Chapter 11.2. @AuthenticationPrincipal
Solution Spring-Security 4.0
Cela fonctionne comme la solution Spring 3.2, mais dans Spring 4.0, @AuthenticationPrincipal
et a AuthenticationPrincipalArgumentResolver
été "déplacé" vers un autre package:
(Mais les anciennes classes dans ses anciens packs existent toujours, alors ne les mélangez pas!)
C'est juste écrire
import org.springframework.security.core.annotation.AuthenticationPrincipal;
ModelAndView someRequestHandler(@AuthenticationPrincipal User activeUser) {
...
}
Pour que cela fonctionne, vous devez enregistrer le ( org.springframework.security.web.method.annotation.
) AuthenticationPrincipalArgumentResolver
: soit en "activant", @EnableWebMvcSecurity
soit en enregistrant ce bean dans mvc:argument-resolvers
- de la même manière que je l'ai décrit avec la solution Spring 3.1 ci-dessus.
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver" />
</mvc:argument-resolvers>
</mvc:annotation-driven>
@Voir Spring Security 5.0 Reference, Chapter 39.3 @AuthenticationPrincipal
(id="applicationConversionService")
dans l'exempleAlors que Ralphs Answer fournit une solution élégante, avec Spring Security 3.2, vous n'avez plus besoin de mettre en œuvre la vôtre
ArgumentResolver
.Si vous avez une
UserDetails
implémentationCustomUser
, vous pouvez simplement faire ceci:Voir la documentation sur la sécurité Spring: @AuthenticationPrincipal
la source
@EnableWebMvcSecurity
ou en XML:<mvc:annotation-driven> <mvc:argument-resolvers> <bean class="org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver" /> </mvc:argument-resolvers> </mvc:annotation-driven>
customUser
est nul ou non?if (customUser != null) { ... }
Spring Security est conçu pour fonctionner avec d'autres frameworks non Spring, il n'est donc pas étroitement intégré à Spring MVC. Spring Security renvoie l'
Authentication
objet de laHttpServletRequest.getUserPrincipal()
méthode par défaut, c'est donc ce que vous obtenez en tant que principal. Vous pouvez obtenir votreUserDetails
objet directement à partir de celui-ci en utilisantNotez également que les types d'objets peuvent varier en fonction du mécanisme d'authentification utilisé (il se peut que vous n'obteniez pas de a
UsernamePasswordAuthenticationToken
, par exemple) et que leAuthentication
ne doit pas strictement contenir deUserDetails
. Il peut s'agir d'une chaîne ou de tout autre type.Si vous ne souhaitez pas appeler
SecurityContextHolder
directement, l'approche la plus élégante (que je suivrais) consiste à injecter votre propre interface d'accesseur de contexte de sécurité personnalisée qui est personnalisée pour correspondre à vos besoins et à vos types d'objet utilisateur. Créez une interface, avec les méthodes appropriées, par exemple:Vous pouvez ensuite l'implémenter en accédant au
SecurityContextHolder
dans votre implémentation standard, découplant ainsi entièrement votre code de Spring Security. Ensuite, injectez-le dans les contrôleurs qui ont besoin d'accéder aux informations de sécurité ou aux informations sur l'utilisateur actuel.L'autre avantage principal est qu'il est facile de faire des implémentations simples avec des données fixes pour les tests, sans avoir à se soucier de remplir les locals des threads, etc.
la source
Implémentez l'
HandlerInterceptor
interface, puis injectez leUserDetails
dans chaque requête qui a un modèle, comme suit:la source
<mvc:interceptors>
dans mon fichier de configuration d'application.spring-security-taglibs
: stackoverflow.com/a/44373331/548473À partir de Spring Security version 3.2, la fonctionnalité personnalisée qui a été implémentée par certaines des réponses les plus anciennes, existe prête à l'emploi sous la forme de l'
@AuthenticationPrincipal
annotation qui est soutenue parAuthenticationPrincipalArgumentResolver
.Un exemple simple de son utilisation est:
CustomUser doit être assignable à partir de
authentication.getPrincipal()
Voici les Javadocs correspondants de AuthenticationPrincipal et AuthenticationPrincipalArgumentResolver
la source
la source
Et si vous avez besoin d'un utilisateur autorisé dans les modèles (par exemple JSP), utilisez
ensemble avec
la source
Vous pouvez essayer ceci: En utilisant l'objet d'authentification de Spring, nous pouvons obtenir les détails de l'utilisateur dans la méthode du contrôleur. Voici l'exemple, en passant l'objet d'authentification dans la méthode du contrôleur avec l'argument. Une fois que l'utilisateur est authentifié, les détails sont renseignés dans l'objet d'authentification.
la source