Преамбула: Начиная с Spring-Security 3.2, @AuthenticationPrincipal
в конце этого ответа есть хорошая аннотация . Это лучший способ, когда вы используете Spring-Security> = 3.2.
Когда ты:
- использовать старую версию Spring-Security,
- необходимо загрузить пользовательский объект пользователя из базы данных с помощью некоторой информации (например, имени входа или идентификатора), хранящейся в основной или
- хотите узнать, как
HandlerMethodArgumentResolver
или WebArgumentResolver
может решить эту проблему элегантным способом, или просто хотите изучить фон @AuthenticationPrincipal
и AuthenticationPrincipalArgumentResolver
(потому что он основан на HandlerMethodArgumentResolver
)
затем продолжайте читать - иначе просто используйте @AuthenticationPrincipal
и поблагодарите Роба Винча (Автор @AuthenticationPrincipal
) и Лукаса Шмельцайзена (за его ответ).
(Кстати: мой ответ немного старше (январь 2012 г.), поэтому именно Лукас Шмельцайзен выступил первым с @AuthenticationPrincipal
базой решений для аннотаций в Spring Security 3.2.)
Тогда вы можете использовать в своем контроллере
public ModelAndView someRequestHandler(Principal principal) {
User activeUser = (User) ((Authentication) principal).getPrincipal();
...
}
Это нормально, если вам это нужно один раз. Но если вам это нужно в несколько раз, это уродливо, потому что оно загрязняет ваш контроллер деталями инфраструктуры, что обычно должно быть скрыто платформой.
Так что вы действительно хотите иметь такой контроллер:
public ModelAndView someRequestHandler(@ActiveUser User activeUser) {
...
}
Поэтому вам нужно только реализовать WebArgumentResolver
. У него есть метод
Object resolveArgument(MethodParameter methodParameter,
NativeWebRequest webRequest)
throws Exception
Он получает веб-запрос (второй параметр) и должен возвращать User
if, если он чувствует себя ответственным за аргумент метода (первый параметр).
С весны 3.1 появилась новая концепция HandlerMethodArgumentResolver
. Если вы используете Spring 3.1+, то вам следует использовать его. (Это описано в следующем разделе этого ответа))
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;
}
}
}
Вам необходимо определить пользовательскую аннотацию - вы можете пропустить ее, если каждый экземпляр User всегда должен быть взят из контекста безопасности, но никогда не является объектом команды.
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ActiveUser {}
В конфигурации вам нужно только добавить это:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"
id="applicationConversionService">
<property name="customArgumentResolver">
<bean class="CurrentUserWebArgumentResolver"/>
</property>
</bean>
@ См. Научитесь настраивать аргументы метода Spring MVC @Controller.
Следует отметить, что если вы используете Spring 3.1, они рекомендуют HandlerMethodArgumentResolver вместо WebArgumentResolver. - см. комментарий от Джея
То же самое с HandlerMethodArgumentResolver
для весны 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;
}
}
}
В настройку нужно добавить это
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="CurrentUserHandlerMethodArgumentResolver"/>
</mvc:argument-resolvers>
</mvc:annotation-driven>
@ См. Использование интерфейса Spring MVC 3.1 HandlerMethodArgumentResolver
Решение Spring-Security 3.2
Spring Security 3.2 (не путайте с Spring 3.2) имеет собственное встроенное решение: @AuthenticationPrincipal
( org.springframework.security.web.bind.annotation.AuthenticationPrincipal
). Это хорошо описано в ответе Лукаса Шмельцайзена
Просто пишу
ModelAndView someRequestHandler(@AuthenticationPrincipal User activeUser) {
...
}
Чтобы это работало, вам нужно зарегистрировать AuthenticationPrincipalArgumentResolver
( org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver
): либо «активировать», @EnableWebMvcSecurity
либо зарегистрировать этот bean-компонент внутри mvc:argument-resolvers
- так же, как я описал это с помощью решения Spring 3.1 выше.
@ См. Spring Security 3.2. Ссылка, глава 11.2. @AuthenticationPrincipal
Решение Spring-Security 4.0
Он работает как 3.2 решения Spring, но весной 4.0, @AuthenticationPrincipal
и AuthenticationPrincipalArgumentResolver
был «перемещен» на другой пакет:
(Но старые классы в старых пакетах все еще существуют, поэтому не смешивайте их!)
Просто пишу
import org.springframework.security.core.annotation.AuthenticationPrincipal;
ModelAndView someRequestHandler(@AuthenticationPrincipal User activeUser) {
...
}
Чтобы это работало, вам нужно зарегистрировать ( org.springframework.security.web.method.annotation.
) AuthenticationPrincipalArgumentResolver
: либо «активировать», @EnableWebMvcSecurity
либо зарегистрировать этот bean-компонент внутри mvc:argument-resolvers
- так же, как я описал это с помощью решения Spring 3.1 выше.
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver" />
</mvc:argument-resolvers>
</mvc:annotation-driven>
@ См. Spring Security 5.0 Справочник, Глава 39.3 @AuthenticationPrincipal
(id="applicationConversionService")
в примереВ то время как Ralphs Answer предоставляет элегантное решение, в Spring Security 3.2 вам больше не нужно внедрять свои собственные
ArgumentResolver
.Если у вас есть
UserDetails
реализацияCustomUser
, вы можете просто сделать это:См. Документацию Spring Security: @AuthenticationPrincipal
источник
@EnableWebMvcSecurity
или в XML:<mvc:annotation-driven> <mvc:argument-resolvers> <bean class="org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver" /> </mvc:argument-resolvers> </mvc:annotation-driven>
customUser
null или нет?if (customUser != null) { ... }
Spring Security предназначен для работы с другими средами, отличными от Spring, поэтому он тесно не интегрирован с Spring MVC. Spring Security возвращает
Authentication
объект изHttpServletRequest.getUserPrincipal()
метода по умолчанию, поэтому вы получаете его в качестве принципала. Вы можете получить свойUserDetails
объект непосредственно с помощьюТакже обратите внимание, что типы объектов могут различаться в зависимости от используемого механизма аутентификации (например, вы можете не получить a
UsernamePasswordAuthenticationToken
), иAuthentication
он не обязательно должен содержать aUserDetails
. Это может быть строка или любой другой тип.Если вы не хотите звонить
SecurityContextHolder
напрямую, самый элегантный подход (которому я бы следовал) - внедрить свой собственный интерфейс доступа к контексту безопасности, настроенный в соответствии с вашими потребностями и типами пользовательских объектов. Создайте интерфейс с соответствующими методами, например:Затем вы можете реализовать это, обратившись к
SecurityContextHolder
стандартной реализации, таким образом полностью отделив свой код от Spring Security. Затем введите это в контроллеры, которым необходим доступ к информации о безопасности или информации о текущем пользователе.Другое основное преимущество заключается в том, что можно легко создавать простые реализации с фиксированными данными для тестирования, не беспокоясь о заполнении локальных потоков и т. Д.
источник
Реализуйте
HandlerInterceptor
интерфейс, а затем вставьтеUserDetails
в каждый запрос, который имеет модель, следующим образом:источник
<mvc:interceptors>
в мой файл конфигурации приложения.spring-security-taglibs
: stackoverflow.com/a/44373331/548473Начиная с версии Spring Security 3.2, пользовательские функции, реализованные в некоторых предыдущих ответах, существуют сразу после установки в виде
@AuthenticationPrincipal
аннотации, которая поддерживаетсяAuthenticationPrincipalArgumentResolver
.Простой пример его использования:
CustomUser должен быть назначен из
authentication.getPrincipal()
Вот соответствующие Javadocs AuthenticationPrincipal и AuthenticationPrincipalArgumentResolver
источник
источник
И если вам нужен авторизованный пользователь в шаблонах (например, JSP), используйте
вместе с
источник
Вы можете попробовать это: Используя Authentication Object из Spring, мы можем получить от него данные о пользователе в методе контроллера. Ниже приведен пример, передавая объект Authentication в методе контроллера вместе с аргументом. Когда пользователь проходит аутентификацию, детали заполняются в объекте Authentication.
источник