Authentication
Authentication is the process of proving who you are. It's like showing your ID at the door โ the bouncer checks it, and if it looks legit, you get in. Without authentication, everyone is anonymous and you have no idea who's using your app.
Spring Security makes authentication flexible. You can authenticate users from a database, LDAP, OAuth providers, or even in-memory for testing. The key is implementing UserDetailsService to tell Spring where to find your users.
UserDetailsService
UserDetailsService is the interface that loads user data. You implement it to fetch users from your database, file system, or wherever you store them. Spring Security calls this service whenever someone tries to log in.
The method is simple: give it a username, and it returns a UserDetails object containing the password and authorities. Spring Security then compares the password with what the user sent.
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found: " + username));
return org.springframework.security.core.userdetails.User.builder()
.username(user.getUsername())
.password(user.getPassword())
.roles(user.getRole())
.build();
}
}
Password Encoding
Never, ever store passwords in plain text. I mean it. Use BCrypt or another password encoder. Spring Security provides a PasswordEncoder that handles hashing for you. It's like putting your passwords through a shredder โ you can't reverse it, but you can verify matches.
BCrypt is the industry standard because it includes a random salt with each password. Even if two users have the same password, their hashes will be different.
@Configuration
public class PasswordConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
@Service
public class UserService {
@Autowired
private PasswordEncoder passwordEncoder;
public User createUser(String username, String password) {
User user = new User();
user.setUsername(username);
user.setPassword(passwordEncoder.encode(password));
return userRepository.save(user);
}
}
Login Form Configuration
By default, Spring Security provides a login form at /login. You can customize it to use your own login page or switch to stateless authentication with JWT tokens. The choice depends on your app type โ web apps usually want a form, while APIs want tokens.
For web applications, you can point Spring Security to your custom login page. For REST APIs, most people use JWT or OAuth2 tokens instead of session-based login.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.formLogin(form -> form
.loginPage("/login")
.defaultSuccessUrl("/dashboard")
.permitAll()
)
.logout(logout -> logout
.logoutSuccessUrl("/login?logout")
.permitAll()
);
return http.build();
}