Spring Security Fundamentals
Security Architecture
Section titled “Security Architecture”flowchart LR
Client -->|Basic Auth| SecurityFilter
SecurityFilter --> UserDetailsService
UserDetailsService --> InMemory["InMemoryUserDetailsManager or Database"]
SecurityFilter --> Controller
Security Configuration
Section titled “Security Configuration”@Configuration@EnableWebSecuritypublic class SpringSecurityConfig {
@Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }
@Bean public UserDetailsService userDetailsService() { UserDetails user = User.withUsername("user") .password(passwordEncoder().encode("root")) .roles("USER") .build();
return new InMemoryUserDetailsManager(user); }
@Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http .csrf(csrf -> csrf.disable()) .authorizeHttpRequests(auth -> auth .anyRequest().authenticated()) .httpBasic(Customizer.withDefaults());
return http.build(); }}SecurityFilterChain
Section titled “SecurityFilterChain”SecurityFilterChain defines how incoming HTTP requests are secured.
Example:
http.csrf(csrf -> csrf.disable()) .authorizeHttpRequests(auth -> auth .requestMatchers("/public/**").permitAll() .anyRequest().authenticated()) .httpBasic(Customizer.withDefaults());Important Rule
Section titled “Important Rule”anyRequest() must appear only once and last.
Incorrect:
http.authorizeHttpRequests(a -> a.anyRequest().authenticated());
http.authorizeHttpRequests(a -> a.anyRequest().authenticated());Produces:
Can't configure anyRequest after itselfUserDetailsService
Section titled “UserDetailsService”Spring Security needs to know:
- Username
- Password
- Roles
For demos, users can be stored in memory.
@Beanpublic UserDetailsService userDetailsService() {
UserDetails user = User.withUsername("user") .password(passwordEncoder().encode("root")) .roles("USER") .build();
return new InMemoryUserDetailsManager(user);}Production
Section titled “Production”Instead of memory, implement UserDetailsService that loads users from the database.
PasswordEncoder
Section titled “PasswordEncoder”BCrypt
Section titled “BCrypt”@Beanpublic PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder();}Generate a password:
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
System.out.println(encoder.encode("root"));Store the generated hash in the database.
NoOp (Testing Only)
Section titled “NoOp (Testing Only)”.password("{noop}root")Never use {noop} in production.
Basic Authentication
Section titled “Basic Authentication”Since httpBasic() is enabled, clients send:
Authorization: Basic base64(user:root)curl -u user:root http://localhost:8080/employeesPostman
Section titled “Postman”- Authorization
- Basic Auth
- Username: user
- Password: root
Common Errors
Section titled “Common Errors”Encoded password does not look like BCrypt
Section titled “Encoded password does not look like BCrypt”Cause:
- Stored password is plain text
- BCryptPasswordEncoder is configured
Fix:
- Encode passwords before storing.
- Or use
{noop}only for testing.
Can’t configure anyRequest after itself
Section titled “Can’t configure anyRequest after itself”Cause:
Multiple calls to anyRequest().
Fix:
Only one authorizeHttpRequests() chain and one anyRequest().
Application Security vs Database Security
Section titled “Application Security vs Database Security”| Application Security | Database Security |
|---|---|
| Spring Security | MySQL/PostgreSQL authentication |
| Controls API access | Controls DB login |
| Users, roles, authorities | Database users |
These are completely different concerns.
Authentication Flow
Section titled “Authentication Flow”sequenceDiagram
participant Client
participant Spring
participant UserDetailsService
Client->>Spring: username/password
Spring->>UserDetailsService: loadUserByUsername()
UserDetailsService-->>Spring: UserDetails
Spring->>Spring: Validate password
Spring-->>Client: 200 or 401
Best Practices
Section titled “Best Practices”- Use BCrypt for password storage.
- Never store plain-text passwords.
- Keep one SecurityFilterChain.
- Place
anyRequest()last. - Use a database-backed
UserDetailsServicein production. - Prefer JWT/OAuth2 for stateless APIs.
Key Takeaways
Section titled “Key Takeaways”SecurityFilterChaindefines endpoint security.UserDetailsServicesupplies users during authentication.PasswordEncoderprotects stored passwords.BCryptPasswordEncoderrequires BCrypt hashes.- Spring Security authenticates application users, not database users.