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
(id="applicationConversionService")
no exemploEnquanto o Ralphs Answer fornece uma solução elegante, com o Spring Security 3.2, você não precisa mais implementar o seu
ArgumentResolver
.Se você possui uma
UserDetails
implementaçãoCustomUser
, basta fazer o seguinte:Consulte a documentação de segurança do Spring: @AuthenticationPrincipal
fonte
@EnableWebMvcSecurity
ou em XML:<mvc:annotation-driven> <mvc:argument-resolvers> <bean class="org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver" /> </mvc:argument-resolvers> </mvc:annotation-driven>
customUser
é nulo ou não?if (customUser != null) { ... }
O Spring Security se destina a trabalhar com outras estruturas que não são do Spring, portanto, não está totalmente integrado ao Spring MVC. O Spring Security retorna o
Authentication
objeto doHttpServletRequest.getUserPrincipal()
método por padrão, e é isso que você obtém como principal. Você pode obter seuUserDetails
objeto diretamente disso usandoObserve também que os tipos de objetos podem variar dependendo do mecanismo de autenticação usado (você pode não obter um
UsernamePasswordAuthenticationToken
, por exemplo) eAuthentication
não precisa estritamente conter umUserDetails
. Pode ser uma string ou qualquer outro tipo.Se você não deseja ligar
SecurityContextHolder
diretamente, a abordagem mais elegante (que eu seguiria) é injetar sua própria interface acessora de contexto de segurança personalizada, personalizada para atender às suas necessidades e tipos de objeto do usuário. Crie uma interface, com os métodos relevantes, por exemplo:Em seguida, você pode implementar isso acessando o
SecurityContextHolder
em sua implementação padrão, dissociando completamente seu código do Spring Security. Em seguida, injete isso nos controladores que precisam acessar informações de segurança ou informações sobre o usuário atual.O outro principal benefício é que é fácil fazer implementações simples com dados fixos para teste, sem ter que se preocupar com o preenchimento de locais de encadeamento e assim por diante.
fonte
Implemente a
HandlerInterceptor
interface e injete aUserDetails
em cada solicitação que possui um Modelo, da seguinte maneira:fonte
<mvc:interceptors>
arquivo de configuração do meu aplicativo.spring-security-taglibs
: stackoverflow.com/a/44373331/548473Começando com o Spring Security versão 3.2, a funcionalidade personalizada que foi implementada por algumas das respostas mais antigas existe imediatamente, na forma da
@AuthenticationPrincipal
anotação suportadaAuthenticationPrincipalArgumentResolver
.Um exemplo simples de seu uso é:
O CustomUser precisa ser atribuído a partir de
authentication.getPrincipal()
Aqui estão os Javadocs correspondentes de AuthenticationPrincipal e AuthenticationPrincipalArgumentResolver
fonte
fonte
E se você precisar de um usuário autorizado em modelos (por exemplo, JSP), use
junto com
fonte
Você pode tentar o seguinte: Usando o Authentication Object da Spring, podemos obter detalhes do usuário no método do controlador. Abaixo está o exemplo, passando o objeto de autenticação no método do controlador junto com o argumento. Uma vez que o usuário é autenticado, os detalhes são preenchidos no objeto de autenticação.
fonte