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