Preâmbulo: Desde o Spring-Security 3.2, há uma boa anotação @AuthenticationPrincipal
descrita no final desta resposta. Este é o melhor caminho a seguir quando você usa Spring-Security> = 3.2.
Quando você:
- use uma versão mais antiga do Spring-Security,
- É necessário carregar seu objeto de usuário personalizado do banco de dados com algumas informações (como o login ou o ID) armazenadas no principal ou
- deseja aprender como
HandlerMethodArgumentResolver
ou WebArgumentResolver
pode resolver isso de uma maneira elegante ou apenas deseja aprender os antecedentes @AuthenticationPrincipal
e AuthenticationPrincipalArgumentResolver
(porque é baseado em HandlerMethodArgumentResolver
)
depois continue lendo - senão use @AuthenticationPrincipal
e agradeça a Rob Winch (autor de @AuthenticationPrincipal
) e Lukas Schmelzeisen (por sua resposta).
(BTW: Minha resposta é um pouco mais antiga (janeiro de 2012), por isso foi Lukas Schmelzeisen que surgiu como a primeira com a @AuthenticationPrincipal
solução de anotação baseada em Spring Security 3.2.)
Então você pode usar no seu controlador
public ModelAndView someRequestHandler(Principal principal) {
User activeUser = (User) ((Authentication) principal).getPrincipal();
...
}
Tudo bem se você precisar uma vez. Mas se você precisar dele várias vezes, é feio porque polui seu controlador com detalhes de infraestrutura, que normalmente devem estar ocultos pela estrutura.
Então, o que você pode realmente querer é ter um controlador como este:
public ModelAndView someRequestHandler(@ActiveUser User activeUser) {
...
}
Portanto, você só precisa implementar a WebArgumentResolver
. Tem um método
Object resolveArgument(MethodParameter methodParameter,
NativeWebRequest webRequest)
throws Exception
Isso obtém a solicitação da web (segundo parâmetro) e deve retornar o User
if se sentir responsável pelo argumento do método (o primeiro parâmetro).
Desde a Primavera 3.1, existe um novo conceito chamado HandlerMethodArgumentResolver
. Se você usa o Spring 3.1+, deve usá-lo. (É descrito na próxima seção desta resposta))
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;
}
}
}
É necessário definir a anotação personalizada - você pode ignorá-la se todas as instâncias do usuário sempre forem retiradas do contexto de segurança, mas nunca forem um objeto de comando.
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ActiveUser {}
Na configuração, você só precisa adicionar isso:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"
id="applicationConversionService">
<property name="customArgumentResolver">
<bean class="CurrentUserWebArgumentResolver"/>
</property>
</bean>
@Veja: Aprenda a personalizar argumentos do método Spring MVC @Controller
Observe que, se você estiver usando o Spring 3.1, eles recomendam HandlerMethodArgumentResolver sobre WebArgumentResolver. - ver comentário de Jay
O mesmo HandlerMethodArgumentResolver
para o 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;
}
}
}
Na configuração, você precisa adicionar este
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="CurrentUserHandlerMethodArgumentResolver"/>
</mvc:argument-resolvers>
</mvc:annotation-driven>
@Veja Aproveitando a interface HandlerMethodArgumentResolver do Spring MVC 3.1
Solução Spring-Security 3.2
O Spring Security 3.2 (não confunda com o Spring 3.2) tem solução própria de compilação: @AuthenticationPrincipal
( org.springframework.security.web.bind.annotation.AuthenticationPrincipal
). Isso está bem descrito na resposta de Lukas Schmelzeisen
Está apenas escrevendo
ModelAndView someRequestHandler(@AuthenticationPrincipal User activeUser) {
...
}
Para que isso funcione, é necessário registrar o AuthenticationPrincipalArgumentResolver
( org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver
): "ativando" @EnableWebMvcSecurity
ou registrando este bean mvc:argument-resolvers
- da mesma forma que o descrevi na solução Spring 3.1 acima.
Consulte a Referência do Spring Security 3.2, Capítulo 11.2. @AuthenticationPrincipal
Solução Spring-Security 4.0
Funciona como a solução Spring 3.2, mas no Spring 4.0 o @AuthenticationPrincipal
e AuthenticationPrincipalArgumentResolver
foi "movido" para outro pacote:
(Mas as classes antigas em suas antigas embalagens ainda existem, portanto não as misture!)
Está apenas escrevendo
import org.springframework.security.core.annotation.AuthenticationPrincipal;
ModelAndView someRequestHandler(@AuthenticationPrincipal User activeUser) {
...
}
Para que isso funcione, é necessário registrar o ( org.springframework.security.web.method.annotation.
) AuthenticationPrincipalArgumentResolver
: "ativando" @EnableWebMvcSecurity
ou registrando esse bean mvc:argument-resolvers
- da mesma forma que o descrevi na solução Spring 3.1 acima.
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver" />
</mvc:argument-resolvers>
</mvc:annotation-driven>
@ Consulte Spring Security 5.0 Reference, Capítulo 39.3 @AuthenticationPrincipal