Lock down your API — configure the security filter chain, authenticate users with a UserDetailsService and password encoder, and authorize requests by role.
Why: spring-boot-starter-security secures every endpoint by default the moment you add it — all requests need authentication, with a generated password printed at startup. Note: from here you replace those defaults with your own configuration.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>Why: a SecurityFilterChain bean is where you declare the rules — which paths are public, which need a role, and how users log in. Note: authentication runs as a chain of servlet filters in front of your controllers; this bean configures that chain.
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/books/**").permitAll() // public reads
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated())
.httpBasic(Customizer.withDefaults());
return http.build();
}
}Why authentication: proving who the user is. Note: implement UserDetailsService to load a user by username from your own table, and expose a PasswordEncoder bean so passwords are stored hashed (BCrypt), never in plain text.
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(); // one-way hashing
}
@Bean
UserDetailsService userDetailsService(UserRepository users) {
return username -> users.findByUsername(username)
.map(u -> User.withUsername(u.getUsername())
.password(u.getPasswordHash()) // already BCrypt-hashed
.roles(u.getRole())
.build())
.orElseThrow(() -> new UsernameNotFoundException(username));
}Note: the authenticated user lives in the SecurityContext. Inject it into a controller method with @AuthenticationPrincipal, or read SecurityContextHolder anywhere. This is how an endpoint knows who is calling it.
@GetMapping("/api/me")
public String me(@AuthenticationPrincipal UserDetails user) {
return "Logged in as " + user.getUsername();
}