Ao configurar o Spring Security em um projeto Spring Boot, o comportamento padrão geralmente fornece apenas um usuário gerado automaticamente. Para gerenciar múltiplas credenciais e perfis de acesso de forma simples, sem a necessidade imediata de um banco de dados, podemos utilizar a autenticação baseada em memória.
Existem duas abordagens principais para implementar esse modelo, conforme detalhado a seguir.
1. Configuração via Adaptador de Segurança
Uma das formas de definir usuários é estendendo a classe WebSecurityConfigurerAdapter e sobrescrevendo o método de gerenciamento de autenticação. É fundamental definir um codificador de senhas (PasswordEncoder), pois o Spring Security exige que as senhas armazenadas sigam um padrão de hash para validação.
@Configuration
public class SecurityConfigurador extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder criptografiaSenha() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder gerenciadorAuth) throws Exception {
// Define o codificador para os usuários em memória
User.UserBuilder usuarios = User.builder().passwordEncoder(criptografiaSenha()::encode);
gerenciadorAuth.inMemoryAuthentication()
.withUser(usuarios.username("admin").password("admin123").roles("ADMIN"))
.withUser(usuarios.username("operador").password("op456").roles("USER"));
}
}
No exemplo acima, criamos dois usuários distintos com papéis (roles) diferentes. Sem o BCryptPasswordEncoder, o sistema falharia ao tentar comparar a senha digitada com a armazenada, resultando em erro de autenticação mesmo com os dados corretos.
2. Implementação via Bean UserDetailsService
Uma abordagem mais modular e moderna consiste em expor um Bean do tipo UserDetailsService. Essa estratégia é útil pois isola a fonte de dados dos usuários, facilitando uma futura migração para consultas em banco de dados SQL ou NoSQL.
@Configuration
public class GestaoUsuariosConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public UserDetailsService provedorUsuarios(PasswordEncoder encoder) {
// Criando usuários detalhados
UserDetails user1 = User.builder()
.passwordEncoder(encoder::encode)
.username("dev_senior")
.password("java888")
.roles("DEVELOPER")
.build();
UserDetails user2 = User.builder()
.passwordEncoder(encoder::encode)
.username("manager")
.password("pass999")
.roles("MANAGER")
.build();
return new InMemoryUserDetailsManager(user1, user2);
}
}
Nesse modelo, utilizamos o InMemoryUserDetailsManager, que é uma implementação pronta do Spring para gerenciar o armazenamento volátil de credenciais.
3. Verificação de Autenticação
Para testar se a autenticação está funcionando corretamente e identificar qual usuário está logado, podemos criar um endpoint REST que recupera os detalhes do contexto de segurança da aplicação.
@RestController
public class StatusController {
private String recuperarNomeLogado() {
Object informacao = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (informacao instanceof UserDetails) {
return ((UserDetails) informacao).getUsername();
}
return informacao.toString();
}
@GetMapping("/info-acesso")
public String verificarStatus() {
String usuarioAtual = recuperarNomeLogado();
return "Sessão ativa para o usuário: " + usuarioAtual;
}
}
Ao acessar o endpoint /info-acesso, o sistema solicitará o login via formulário padrão ou Basic Auth. Após o sucesso, o nome do usuário definido em memória será retornado na resposta da requisição.