Ответ 1
Преамбула: Начиная с 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
, если он чувствует себя ответственным за аргумент метода (первый параметр).
С весны 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
, либо зарегистрировав этот компонент в mvc:argument-resolvers
- так же, как я описал его с помощью решения Spring 3.1. выше.
@См. Spring Security 3.2. Ссылка, глава 11.2. @AuthenticationPrincipal
Решение Spring-Security 4.0
Он работает как решение Spring 3.2, но в Spring 4.0 @AuthenticationPrincipal
и AuthenticationPrincipalArgumentResolver
были "перемещены" в другой пакет:
org.springframework.security.core.annotation.AuthenticationPrincipal
org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver
(Но старые классы в старых пакетах все еще существуют, поэтому не смешивайте их!)
Это просто пишет
import org.springframework.security.core.annotation.AuthenticationPrincipal;
ModelAndView someRequestHandler(@AuthenticationPrincipal User activeUser) {
...
}
Чтобы это работало, вам нужно зарегистрировать (org.springframework.security.web.method.annotation.
) AuthenticationPrincipalArgumentResolver
: либо "активировав" @EnableWebMvcSecurity
, либо зарегистрировав этот бин в 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>
@See Справочник по Spring Security 5.0, глава 39.3 @AuthenticationPrincipal