Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

[Dúvida] Diferença entre a classe UserDetailsService e controller que AuthenticationController

Boa noite,

Durante o curso o instrutor criou a classe que implement UserDetailsService, responsável por buscar o usuario en base dados, também criou outra classe Controller que cria um objeto do tipo new UsernamePasswordAuthenticationToken() e utiliza AuthenticationManager.authenticate() para atuenticar o usuário no contexto do Spring. Sei que na própria documentação do Spring Security diz que si queremos autenticar um usuário via Rest é nossa responsabilidade realizar a implementação desse método. Porém, se o método loadUserByUsername(String username) da classe UserDetailsService já autentica o usuário, por que é necessário criar o UsernamePasswordAuthenticationToken() e autenticar com o AuthenticationManager?

Deste já agradeço.

2 respostas
solução!

Oi Lauro, eu não sou nenhum especialista nisso, mas pelo que entendi é assim...

O método loadUserByUsername de UserDetailsService não é um método autenticador, na verdade, ele é um método simples de consulta, onde ele recupera o nosso objeto User do banco de dados pelo username (login). Esse método será utilizado pelo Spring por baixo dos panos no processo de autenticação, ou seja, ele faz parte desse processo, mas ele em si não é o processo.

Agora no método de login lá no Controller:

  • O UsernamePasswordAuthenticationToken é um token de autenticação por login e senha. Ele "empacota" essas informações para ser usado a seguir no processo de authenticação de fato, que é realizado por um AuthenticationManager.

  • A seguir chamamos o método authenticate() da interface AuthenticationManager

Authentication authenticate(Authentication authentication) throws AuthenticationException;

Como podemos ver pela assinatura do método, ele recebe um objeto Authenticate. O objeto UsernamePasswordAuthenticationToken tem essa uma relação de herança com com a interface Authenticate, ele extende de AbstractAuthenticationToken que por sua vez implementa a interface Authenticate, por isso ele é aceito como parâmetro para o método sem problemas.

É nesse método authenticate() que acontece a magia da autenticação. Nesse método, o AuthenticationManager irá procurar um provedor de autenticação adequado para validar esse token (UsernamePasswordAuthenticationToken) - nós podemos criar um provedor de autenticação personalizado implementando a interface AuthenticationProvider, mas nesse projeto não fazemos isso, usamos o provedor de autenticação padrão do Spring -, caso o AuthenticationManager não encontre um provedor de autenticação, ele irá usar o provedor padrão, o DaoAuthenticationProvider.

É esse DaoAuthenticationProvider que irá chamar o método loadUserByUsername(), para recuperar os dados do usuário do banco de dados e comparar se os dados recuperados batem com os dados que passamos pelo request. Mas se ele tentar comparar password com password não vai dar certo, pois a senha do banco está criptografada e a do request não. Para isso que nós criamos uma @Bean lá no SecurityConfigurations:

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

A grosso modo, o Spring injeta essa bean no DaoAuthenticationProvider, permitindo assim que ele criptografe a senha do request e consiga fazer a validação da senha-client x senha-database.

Se a autenticação der certo o método authenticate() irá retornar um objeto Authentication, através do método getPrincipal() recuperamos um objeto UserDetails, que pode ser parseado para a nossa classe de usuário.

  • Em seguida ele finalmente gera um JWT
  • Retorna esse JWT pro cliente

Espero que eu tenha entendido a sua dúvida e sanado ela. Se eu falei algo errado, por favor me corrijam.

Espero que isso tenha sido útil. Bons estudos!

Olá Mateus,

Depois de refletir na tua explicação e analisar o código da classe Controller responsável por autenticar, entendi para o que server a classe UsernamePasswordAuthenticationToken e também o método manager.authenticate(authenticationToken).

Desconocia que o méotdo authenticate do authenticationManager compara a senha guardada em base de dados com a senha vinda da request.

Obrigado pela ajuda!

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software