Präambel: Seit Spring-Security 3.2 ist @AuthenticationPrincipal
am Ende dieser Antwort eine nette Anmerkung beschrieben. Dies ist der beste Weg, wenn Sie Spring-Security> = 3.2 verwenden.
Wenn du:
- Verwenden Sie eine ältere Version von Spring-Security.
- Sie müssen Ihr benutzerdefiniertes Benutzerobjekt aus der Datenbank mit einigen Informationen (wie dem Login oder der ID) laden, die im Principal oder gespeichert sind
- wollen lernen, wie ein
HandlerMethodArgumentResolver
oder WebArgumentResolver
dies auf elegante Weise lösen kann, oder wollen einfach nur den Hintergrund hinter @AuthenticationPrincipal
und lernen AuthenticationPrincipalArgumentResolver
(weil es auf a basiert HandlerMethodArgumentResolver
)
dann lesen Sie weiter - sonst verwenden Sie einfach @AuthenticationPrincipal
und danken Sie Rob Winch (Autor von @AuthenticationPrincipal
) und Lukas Schmelzeisen (für seine Antwort).
(Übrigens: Meine Antwort ist etwas älter (Januar 2012), daher war es Lukas Schmelzeisen , der als erster die @AuthenticationPrincipal
Annotation-Lösungsbasis auf Spring Security 3.2 aufstellte .)
Dann können Sie in Ihrem Controller verwenden
public ModelAndView someRequestHandler(Principal principal) {
User activeUser = (User) ((Authentication) principal).getPrincipal();
...
}
Das ist in Ordnung, wenn Sie es einmal brauchen. Wenn Sie es jedoch mehrmals benötigen, ist es hässlich, weil es Ihren Controller mit Infrastrukturdetails verschmutzt. Dies sollte normalerweise vom Framework ausgeblendet werden.
Was Sie also wirklich wollen, ist ein Controller wie dieser:
public ModelAndView someRequestHandler(@ActiveUser User activeUser) {
...
}
Daher müssen Sie nur a implementieren WebArgumentResolver
. Es hat eine Methode
Object resolveArgument(MethodParameter methodParameter,
NativeWebRequest webRequest)
throws Exception
Das erhält die Webanforderung (zweiter Parameter) und muss die zurückgeben, User
wenn es sich für das Methodenargument (den ersten Parameter) verantwortlich fühlt.
Seit Frühjahr 3.1 gibt es ein neues Konzept namens HandlerMethodArgumentResolver
. Wenn Sie Spring 3.1+ verwenden, sollten Sie es verwenden. (Es wird im nächsten Abschnitt dieser Antwort beschrieben))
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;
}
}
}
Sie müssen die benutzerdefinierte Anmerkung definieren - Sie können sie überspringen, wenn jede Instanz des Benutzers immer aus dem Sicherheitskontext entnommen werden soll, aber niemals ein Befehlsobjekt ist.
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ActiveUser {}
In der Konfiguration müssen Sie nur Folgendes hinzufügen:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"
id="applicationConversionService">
<property name="customArgumentResolver">
<bean class="CurrentUserWebArgumentResolver"/>
</property>
</bean>
@See: Erfahren Sie, wie Sie die Argumente der Spring MVC @Controller-Methode anpassen
Wenn Sie Spring 3.1 verwenden, empfehlen sie HandlerMethodArgumentResolver gegenüber WebArgumentResolver. - siehe Kommentar von Jay
Gleiches gilt HandlerMethodArgumentResolver
für 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;
}
}
}
In der Konfiguration müssen Sie dies hinzufügen
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="CurrentUserHandlerMethodArgumentResolver"/>
</mvc:argument-resolvers>
</mvc:annotation-driven>
@Siehe Nutzung der Spring MVC 3.1 HandlerMethodArgumentResolver-Schnittstelle
Spring-Security 3.2 Lösung
Spring Security 3.2 (nicht mit Spring 3.2 verwechseln) verfügt über eine eigene integrierte Lösung: @AuthenticationPrincipal
( org.springframework.security.web.bind.annotation.AuthenticationPrincipal
). Dies ist in Lukas Schmelzeisens Antwort gut beschrieben
Es schreibt nur
ModelAndView someRequestHandler(@AuthenticationPrincipal User activeUser) {
...
}
Damit dies funktioniert, müssen Sie AuthenticationPrincipalArgumentResolver
( org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver
) registrieren : entweder durch "Aktivieren" @EnableWebMvcSecurity
oder durch Registrieren dieser Bean innerhalb mvc:argument-resolvers
- so wie ich es oben mit der Lösung von may Spring 3.1 beschrieben habe.
@ Siehe Spring Security 3.2 Referenz, Kapitel 11.2. @AuthenticationPrincipal
Spring-Security 4.0-Lösung
Es funktioniert wie die Spring 3.2-Lösung, aber in Spring 4.0 wurde das @AuthenticationPrincipal
und AuthenticationPrincipalArgumentResolver
in ein anderes Paket "verschoben":
(Aber die alten Klassen in ihren alten Paketen existieren noch, also mischen Sie sie nicht!)
Es schreibt nur
import org.springframework.security.core.annotation.AuthenticationPrincipal;
ModelAndView someRequestHandler(@AuthenticationPrincipal User activeUser) {
...
}
Damit dies funktioniert, müssen Sie ( org.springframework.security.web.method.annotation.
) registrieren AuthenticationPrincipalArgumentResolver
: entweder durch "Aktivieren" @EnableWebMvcSecurity
oder durch Registrieren dieser Bean innerhalb mvc:argument-resolvers
- so wie ich es oben mit der Lösung von may Spring 3.1 beschrieben habe.
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver" />
</mvc:argument-resolvers>
</mvc:annotation-driven>
@ Siehe Spring Security 5.0-Referenz, Kapitel 39.3 @AuthenticationPrincipal
(id="applicationConversionService")
im Beispiel anzugebenWährend Ralphs Answer eine elegante Lösung bietet, müssen Sie mit Spring Security 3.2 keine eigenen mehr implementieren
ArgumentResolver
.Wenn Sie eine
UserDetails
Implementierung habenCustomUser
, können Sie dies einfach tun:Siehe Spring Security-Dokumentation: @AuthenticationPrincipal
quelle
@EnableWebMvcSecurity
<mvc:annotation-driven> <mvc:argument-resolvers> <bean class="org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver" /> </mvc:argument-resolvers> </mvc:annotation-driven>
customUser
null ist oder nicht?if (customUser != null) { ... }
Spring Security soll mit anderen Nicht-Spring-Frameworks zusammenarbeiten und ist daher nicht eng in Spring MVC integriert. Spring Security gibt das
Authentication
ObjektHttpServletRequest.getUserPrincipal()
standardmäßig von der Methode zurück, sodass Sie dies als Prinzipal erhalten. Sie können IhrUserDetails
Objekt direkt daraus erhalten, indem SieBeachten Sie auch, dass die Objekttypen je nach verwendetem Authentifizierungsmechanismus variieren können (
UsernamePasswordAuthenticationToken
z. B. erhalten Sie möglicherweise kein ) und dass das Objekt nicht unbedingt einAuthentication
enthalten mussUserDetails
. Es kann eine Zeichenfolge oder ein anderer Typ sein.Wenn Sie nicht
SecurityContextHolder
direkt anrufen möchten , besteht der eleganteste Ansatz (dem ich folgen würde) darin, eine eigene benutzerdefinierte Sicherheitskontext-Accessor-Oberfläche einzufügen, die an Ihre Anforderungen und Benutzerobjekttypen angepasst ist. Erstellen Sie eine Schnittstelle mit den entsprechenden Methoden, zum Beispiel:Sie können dies dann implementieren, indem Sie auf das
SecurityContextHolder
in Ihrer Standardimplementierung zugreifen und so Ihren Code vollständig von Spring Security entkoppeln. Fügen Sie dies dann in die Controller ein, die Zugriff auf Sicherheitsinformationen oder Informationen zum aktuellen Benutzer benötigen.Der andere Hauptvorteil besteht darin, dass es einfach ist, einfache Implementierungen mit festen Daten zum Testen durchzuführen, ohne sich um das Auffüllen von Thread-Locals usw. kümmern zu müssen.
quelle
Implementieren Sie die
HandlerInterceptor
Schnittstelle und fügen Sie sie dannUserDetails
wie folgt in jede Anforderung mit einem Modell ein:quelle
<mvc:interceptors>
in meiner Anwendungskonfigurationsdatei hinzufügen .spring-security-taglibs
: stackoverflow.com/a/44373331/548473Ab Spring Security Version 3.2 ist die benutzerdefinierte Funktionalität, die von einigen älteren Antworten implementiert wurde, sofort in Form der
@AuthenticationPrincipal
Anmerkung vorhanden, die von unterstützt wirdAuthenticationPrincipalArgumentResolver
.Ein einfaches Beispiel für seine Verwendung ist:
CustomUser muss von zuweisbar sein
authentication.getPrincipal()
Hier sind die entsprechenden Javadocs von AuthenticationPrincipal und AuthenticationPrincipalArgumentResolver
quelle
quelle
Und wenn Sie autorisierte Benutzer in Vorlagen (zB JSP) benötigen, verwenden Sie
zusammen mit
quelle
Sie können dies versuchen: Mithilfe des Authentifizierungsobjekts von Spring können wir Benutzerdetails in der Controller-Methode abrufen. Im Folgenden finden Sie ein Beispiel für die Übergabe des Authentifizierungsobjekts in der Controller-Methode zusammen mit dem Argument. Sobald der Benutzer authentifiziert ist, werden die Details im Authentifizierungsobjekt ausgefüllt.
quelle