Oi Luccas!
Quase todo o processo de autenticação/autorização é feito pelo Spring Security por baixo dos panos, e justamente por isso acabam surgindo essas dúvidas mesmo que você mencionou. Vou te explicar todo o passo a passo de como funciona o processo:
O controller de autenticação não é do Spring e sim "nosso". Nele, implementamos a lógica que recebe a requisição contendo o username/password do usuário e inicia o processo de autenticação. Essa é a linha que inicia todo o processo de autenticação:
manager.authenticate(authenticationToken);
Essa linha chama o método authenticate
da classe do Spring AuthenticationManager. Para isso, é necessário injetar no controller essa classe do Spring. Por mais que seja uma classe do próprio Spring, essa em específico ele não sabe como injetar sozinho e precisamos ensinar a ele como fazer a injeção. Isso a gente fez na nossa classe SecurityConfigurations
:
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
return configuration.getAuthenticationManager();
}
Esse método anterior serve para ensinar ao Spring como ele deve fazer para criar um objeto do tipo AuthenticationManager
, sempre que precisar injetá-lo em alguma classe.
Quando chamamos o método manager.authenticate(authenticationToken);
o que o Spring faz, por baixo dos panos, é procurar nas configurações do nosso projeto como ele deve realizar o processo de autenticação. Ele vai detectar que temos uma classe que implementa a sua interface UserDetailsService
e então chamará automaticamente o método loadUserByUsername
dela, passando como parâmetro o username:
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return repository.findByLogin(username);
}
Nesse método, implementamos como deve ser feita a lógica de verificar se o username enviado na requisição está válido. Mas e a senha? Não basta apenas checar se o username existe no banco de dados, precisamos checar se a senha está correta também! A verificação da senha é feita por baixo dos panos pelo Spring.
Repare que o método anterior devolve um objeto do tipo UserDetails
, que é uma interface que tivemos que implementar em nossa classe Usuario
e nela fomos obrigados a implementar vários métodos dessa interface, dentre eles o método getPassword
, que devolve a senha do usuário.
Após chamar o método loadUserByUsername
, o Spring faz a checagem da senha, mas agora temos uma outra questão: A senha que vem da requisição está em texto aberto (ex: 123456), mas a senha que veio do banco de dados, e está setada no objeto UserDetails
, está no formato BCrypt. Como o Spring sabe que deve converter a senha de texto aberto para o formato BCrypt antes de realizar a comparação? Novamente, ele vai procurar em nosso projeto qual o PasswordEncoder que deve utilizar, e vai encontar isso na classe SecurityConfigurations
:
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
Pronto! A comparacação será realizada e se a senha estiver certa, significa que a autenticação foi realizada com sucesso. Caso contrário, vai lançar uma exception.
O código então retorna ao método de autenticação de nosso controller:
var authentication = manager.authenticate(authenticationToken);
Repare que a chamada ao método manager.authenticate(authenticationToken);
devolve um objeto do Spring que contém os dados do usuário autenticado. Caso o username ou senha estejam inválidos, não terá nenhum retorno, pois será lançada uma exception e o código será interrompido.
A partir desse ponto, é possível utilizar esse objeto devolvido pelo método authenticate
para se obter o username, password, perfis e quaisquer outras informações referentes ao usuário que acabou de se autenticar.
Perceba como todas as configurações que fizemos no projeto, em relação ao Spring Security, tem um propósito e se encaixam perfeitamente no processo de autenticação do Spring. Porém, como ele faz 90% do trabalho por baixo dos panos, não fica tão obvio de entender como esse processo funciona.
Espero que tenha te ajudado a entender melhor o processo de autenticação do Spring Security.
Bons estudos!