Preambuła: Od Spring-Security 3.2 @AuthenticationPrincipal
na końcu tej odpowiedzi znajduje się ładna adnotacja . To najlepszy sposób, jeśli używasz Spring-Security> = 3.2.
Kiedy ty:
- użyj starszej wersji Spring-Security,
- trzeba załadować niestandardowy obiekt użytkownika z bazy danych za pomocą pewnych informacji (takich jak login lub identyfikator) przechowywanych w pliku głównym lub
- chcesz dowiedzieć się, jak
HandlerMethodArgumentResolver
lub WebArgumentResolver
można rozwiązać ten problem w elegancki sposób, lub po prostu chcesz poznać tło za @AuthenticationPrincipal
i AuthenticationPrincipalArgumentResolver
(ponieważ opiera się na a HandlerMethodArgumentResolver
)
następnie czytaj dalej - w przeciwnym razie użyj @AuthenticationPrincipal
i podziękuj Robowi Winchowi (autorowi @AuthenticationPrincipal
) i Lukasowi Schmelzeisena (za odpowiedź).
(BTW: Moja odpowiedź jest nieco starsza (styczeń 2012), więc to Lukas Schmelzeisen jako pierwszy pojawił się w @AuthenticationPrincipal
rozwiązaniu adnotacji opartym na Spring Security 3.2.)
Następnie możesz użyć w swoim kontrolerze
public ModelAndView someRequestHandler(Principal principal) {
User activeUser = (User) ((Authentication) principal).getPrincipal();
...
}
To jest w porządku, jeśli potrzebujesz tego raz. Ale jeśli potrzebujesz go kilka razy, jest brzydki, ponieważ zanieczyszcza kontroler szczegółami infrastruktury, które normalnie powinny być ukryte przez framework.
Więc to, czego naprawdę możesz chcieć, to mieć taki kontroler:
public ModelAndView someRequestHandler(@ActiveUser User activeUser) {
...
}
Dlatego wystarczy zaimplementować plik WebArgumentResolver
. Ma metodę
Object resolveArgument(MethodParameter methodParameter,
NativeWebRequest webRequest)
throws Exception
Pobiera żądanie sieciowe (drugi parametr) i musi zwrócić, User
jeśli czuje się odpowiedzialny za argument metody (pierwszy parametr).
Od wiosny 3.1 pojawiła się nowa koncepcja o nazwie HandlerMethodArgumentResolver
. Jeśli używasz Spring 3.1+, powinieneś go użyć. (Jest to opisane w następnej sekcji tej odpowiedzi))
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;
}
}
}
Musisz zdefiniować adnotację niestandardową - możesz ją pominąć, jeśli każda instancja użytkownika powinna zawsze pochodzić z kontekstu zabezpieczeń, ale nigdy nie jest obiektem polecenia.
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ActiveUser {}
W konfiguracji wystarczy dodać to:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"
id="applicationConversionService">
<property name="customArgumentResolver">
<bean class="CurrentUserWebArgumentResolver"/>
</property>
</bean>
@ Zobacz : Naucz się dostosowywać argumenty metody Spring MVC @Controller
Należy zauważyć, że jeśli używasz Spring 3.1, zalecają HandlerMethodArgumentResolver zamiast WebArgumentResolver. - patrz komentarz Jay
To samo HandlerMethodArgumentResolver
dotyczy wiosny 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;
}
}
}
W konfiguracji musisz to dodać
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="CurrentUserHandlerMethodArgumentResolver"/>
</mvc:argument-resolvers>
</mvc:annotation-driven>
@See Wykorzystanie interfejsu Spring MVC 3.1 HandlerMethodArgumentResolver
Rozwiązanie Spring-Security 3.2
Spring Security 3.2 (nie mylić z Spring 3.2) ma własne rozwiązanie wbudowane: @AuthenticationPrincipal
( org.springframework.security.web.bind.annotation.AuthenticationPrincipal
). Ładnie to opisuje odpowiedź Lukasa Schmelzeisena
Po prostu pisze
ModelAndView someRequestHandler(@AuthenticationPrincipal User activeUser) {
...
}
Aby to działało, musisz zarejestrować AuthenticationPrincipalArgumentResolver
( org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver
): albo przez "aktywację", @EnableWebMvcSecurity
albo przez zarejestrowanie tego ziarna w mvc:argument-resolvers
- tak samo, jak opisałem to z rozwiązaniem May Spring 3.1 powyżej.
@Patrz Spring Security 3.2 Reference, rozdział 11.2. @AuthenticationPrincipal
Rozwiązanie Spring-Security 4.0
Działa jak rozwiązanie Spring 3.2, ale w wersji Spring 4.0 @AuthenticationPrincipal
i AuthenticationPrincipalArgumentResolver
został „przeniesiony” do innego pakietu:
(Ale stare klasy w starych paczkach nadal istnieją, więc nie mieszaj ich!)
Po prostu pisze
import org.springframework.security.core.annotation.AuthenticationPrincipal;
ModelAndView someRequestHandler(@AuthenticationPrincipal User activeUser) {
...
}
Aby to działało, musisz zarejestrować ( org.springframework.security.web.method.annotation.
) AuthenticationPrincipalArgumentResolver
: albo przez "aktywację", @EnableWebMvcSecurity
albo przez zarejestrowanie tego ziarna w mvc:argument-resolvers
- tak samo, jak opisałem to z rozwiązaniem May Spring 3.1 powyżej.
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver" />
</mvc:argument-resolvers>
</mvc:annotation-driven>
@Patrz Spring Security 5.0 Reference, rozdział 39.3 @AuthenticationPrincipal
(id="applicationConversionService")
w przykładzieChociaż Ralphs Answer zapewnia eleganckie rozwiązanie, dzięki Spring Security 3.2 nie musisz już wdrażać własnego
ArgumentResolver
.Jeśli masz
UserDetails
implementacjęCustomUser
, możesz po prostu zrobić to:Zobacz dokumentację zabezpieczeń Spring: @AuthenticationPrincipal
źródło
@EnableWebMvcSecurity
XML lub w formacie XML:<mvc:annotation-driven> <mvc:argument-resolvers> <bean class="org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver" /> </mvc:argument-resolvers> </mvc:annotation-driven>
customUser
jest null, czy nie?if (customUser != null) { ... }
Spring Security jest przeznaczony do współpracy z innymi frameworkami innymi niż Spring, dlatego nie jest ściśle zintegrowany z Spring MVC. Spring Security domyślnie zwraca
Authentication
obiekt zHttpServletRequest.getUserPrincipal()
metody, więc otrzymujesz to jako podmiot. Możesz uzyskać swójUserDetails
obiekt bezpośrednio z tego za pomocąZauważ również, że typy obiektów mogą się różnić w zależności od używanego mechanizmu uwierzytelniania (możesz
UsernamePasswordAuthenticationToken
na przykład nie dostać ) iAuthentication
nie musi ściśle zawierać plikuUserDetails
. Może to być ciąg lub dowolny inny typ.Jeśli nie chcesz dzwonić
SecurityContextHolder
bezpośrednio, najbardziej eleganckim podejściem (które bym zastosował) jest wstrzyknięcie własnego niestandardowego interfejsu akcesora kontekstu bezpieczeństwa, który jest dostosowany do twoich potrzeb i typów obiektów użytkownika. Utwórz interfejs z odpowiednimi metodami, na przykład:Następnie możesz to zaimplementować, uzyskując dostęp do
SecurityContextHolder
standardowej implementacji, w ten sposób całkowicie oddzielając swój kod od Spring Security. Następnie wstrzyknij to do kontrolerów, które potrzebują dostępu do informacji bezpieczeństwa lub informacji o aktualnym użytkowniku.Inną główną korzyścią jest to, że łatwo jest tworzyć proste implementacje ze stałymi danymi do testowania, bez martwienia się o zapełnianie lokalnych wątków i tak dalej.
źródło
Zaimplementuj
HandlerInterceptor
interfejs, a następnie wstrzyknijUserDetails
do każdego żądania, które ma model, w następujący sposób:źródło
<mvc:interceptors>
w pliku konfiguracyjnym mojej aplikacji.spring-security-taglibs
: stackoverflow.com/a/44373331/548473Począwszy od wersji Spring Security 3.2, niestandardowa funkcjonalność, która została zaimplementowana w niektórych starszych odpowiedziach, istnieje po wyjęciu z pudełka w postaci
@AuthenticationPrincipal
adnotacji, która jest obsługiwana przezAuthenticationPrincipalArgumentResolver
.Prostym przykładem jego użycia jest:
CustomUser musi być przypisywany z
authentication.getPrincipal()
Oto odpowiednie dokumenty Javadocs dotyczące AuthenticationPrincipal i AuthenticationPrincipalArgumentResolver
źródło
źródło
A jeśli potrzebujesz autoryzowanego użytkownika w szablonach (np. JSP) użyj
razem z
źródło
Możesz spróbować tego: Używając obiektu uwierzytelniania Springa możemy uzyskać z niego dane użytkownika w metodzie kontrolera. Poniżej znajduje się przykład, przez przekazanie obiektu Authentication w metodzie kontrolera wraz z argumentem. Gdy użytkownik zostanie uwierzytelniony, szczegóły zostaną wprowadzone do obiektu uwierzytelniania.
źródło