Spring Security

박진석·2025년 2월 6일
post-thumbnail

Spring Security Explained

Spring Security is a powerful framework that handles authentication and authorization in Spring applications.

Core Components and Configuration

Security Configuration

The heart of Spring Security setup is the security configuration class (WebSecurityConfig). This is where we define rules about who can access what in your application:

@Configuration
public class WebSecurityConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                // Public endpoints anyone can access
                .requestMatchers("/public/**", "/api/login").permitAll()
                // Only admins can access these endpoints
                .requestMatchers("/admin/**").hasRole("ADMIN")
                // All other endpoints need authentication
                .anyRequest().authenticated()
            )
            .formLogin(form -> form
                .loginPage("/login")
                .defaultSuccessUrl("/dashboard")
            );
        
        return http.build();
    }
}

Think of this configuration as a security checkpoint. Just like how a building might have different access levels for different areas, this configuration defines which parts of our application require what level of security clearance.

User Management

The User class is our digital identity card in the application. It implements UserDetails to provide Spring Security with essential information about the user:

@Entity
public class User implements UserDetails {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String username;
    private String password;
    private List<GrantedAuthority> authorities;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;  // Returns user's roles and permissions
    }
    
    // Additional UserDetails methods
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }
}

Authentication Service

The UserDetailsService acts like a security guard checking IDs. It loads user information and verifies credentials:

@Service
public class CustomUserDetailsService implements UserDetailsService {
    private final UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String username) {
        return userRepository.findByUsername(username)
            .orElseThrow(() -> new UsernameNotFoundException("User not found"));
    }
}

Password Security

Never store passwords in plain text!!! Spring Security provides password encoders to securely hash passwords:

@Configuration
public class SecurityConfig {
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

@Service
public class UserService {
    private final PasswordEncoder passwordEncoder;
    private final UserRepository userRepository;

    public void createUser(UserRegistrationDTO dto) {
        User user = new User();
        user.setUsername(dto.getUsername());
        // Encode password before saving
        user.setPassword(passwordEncoder.encode(dto.getPassword()));
        userRepository.save(user);
    }
}

Cross-Origin Resource Sharing (CORS)

When your frontend and backend are on different domains (like in modern single-page applications), we need to configure CORS!!!

@Configuration
public class WebSecurityConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .cors(cors -> cors.configurationSource(request -> {
                CorsConfiguration config = new CorsConfiguration();
                config.setAllowedOrigins(Arrays.asList(
                    "http://localhost:3000"
                ));
                config.setAllowedMethods(Arrays.asList(
                    "GET", "POST", "PUT", "DELETE"
                ));
                config.setAllowedHeaders(Arrays.asList("*"));
                return config;
            }))
            .csrf(csrf -> csrf.disable());  // Often disabled for REST APIs
            
        return http.build();
    }
}

Authentication Flow

Here's how the authentication process works:

  1. A user attempts to access a protected resource
  2. Spring Security intercepts the request
  3. If the user isn't authenticated, they're redirected to the login page
  4. The user submits their credentials
  5. Spring Security passes these to the authentication manager
  6. The UserDetailsService loads the user's information
  7. Spring Security compares the submitted password with the stored hash
  8. If successful, the user is granted access and a session is created

Best Practices

  1. Password Security: Always use password encoding - never store plain text passwords.

    user.setPassword(passwordEncoder.encode(rawPassword));
  2. Role-Based Access: Use specific roles for different access levels:

    .requestMatchers("/api/admin/**").hasRole("ADMIN")
    .requestMatchers("/api/user/**").hasRole("USER")
  3. Error Handling: Provide secure but helpful error messages:

    try {
        // Authentication logic
    } catch (AuthenticationException e) {
        return ResponseEntity
            .status(HttpStatus.UNAUTHORIZED)
            .body("Invalid credentials");
    }
  4. Session Management: Configure session management for our needs:

    http.sessionManagement(session -> session
        .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
        .maximumSessions(1)
    );

0개의 댓글