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!