Préambule : Depuis Spring-Security 3.2, il y a une annotation sympathique @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.
Quand vous :
- utiliser une ancienne version de Spring-Security,
- vous devez charger votre objet utilisateur personnalisé à partir de la base de données en fonction de certaines informations (comme le nom d'utilisateur ou l'identifiant) stockées dans le principal ou dans la base de données.
- voulez apprendre comment un
HandlerMethodArgumentResolver
o WebArgumentResolver
peut résoudre ce problème de manière élégante, ou si vous voulez simplement apprendre le contexte de l'opération. @AuthenticationPrincipal
y AuthenticationPrincipalArgumentResolver
(parce qu'il est basé sur un HandlerMethodArgumentResolver
)
alors continuez à lire - sinon, utilisez simplement @AuthenticationPrincipal
et merci à Rob Winch (Auteur de @AuthenticationPrincipal
) y Lukas Schmelzeisen (pour sa réponse).
(BTW : Ma réponse est un peu plus ancienne (janvier 2012), donc elle était Lukas Schmelzeisen qui apparaissent comme le premier avec le @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 laid car cela pollue votre contrôleur avec des détails d'infrastructure, qui devraient normalement être cachés par le framework.
Ce que vous voulez vraiment, c'est un contrôleur comme celui-ci :
public ModelAndView someRequestHandler(@ActiveUser User activeUser) {
...
}
Par conséquent, il suffit d'implémenter un WebArgumentResolver
. Il dispose d'une méthode
Object resolveArgument(MethodParameter methodParameter,
NativeWebRequest webRequest)
throws Exception
qui récupère la requête web (deuxième paramètre) et doit renvoyer la valeur User
si elle se sent responsable de l'argument de la méthode (le premier paramètre).
Depuis Spring 3.1, il existe un nouveau concept appelé HandlerMethodArgumentResolver
. Si vous utilisez Spring 3.1+, vous devriez 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 prise dans le 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 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 @Controller de Spring MVC.
Il est à noter que si vous utilisez Spring 3.1, ils recommandent HandlerMethodArgumentResolver plutôt que 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>
@See Exploitation de l'interface HandlerMethodArgumentResolver de Spring MVC 3.1
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 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" le @EnableWebMvcSecurity
ou en enregistrant ce haricot dans mvc:argument-resolvers
- de la même façon que je l'ai décrit avec la solution Spring 3.1 ci-dessus.
@See Référence Spring Security 3.2, chapitre 11.2. @AuthenticationPrincipal
Solution Spring-Security 4.0
Cela fonctionne comme la solution de Spring 3.2, mais dans Spring 4.0, la fonction @AuthenticationPrincipal
y AuthenticationPrincipalArgumentResolver
a été "déplacé" vers un autre paquet :
(Mais les anciennes classes dans leurs 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 l'option ( org.springframework.security.web.method.annotation.
) AuthenticationPrincipalArgumentResolver
: soit en "activant" @EnableWebMvcSecurity
ou en enregistrant ce haricot dans mvc:argument-resolvers
- de la même façon 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>
@See Référence Spring Security 5.0, Chapitre 39.3 @AuthenticationPrincipal