[Spring Security] 사용자 정의 보안 설정하기

2024. 11. 21. 18:22Framework & Library/Spring Security

 Spring Security 초기화 작업에 대한 큰 틀을 이해했으니 이번에는 사용자(=개발자)가 정의한 보안 설정을 적용해보자. 강의 수강중 작성한 실습 프로젝트는 여기서 확인할 수 있다.

0. 되짚어 보기

 이전 게시글에는 단순하게 "사용자(=개발자)가 정의한 보안 설정이 없다면 기본 보안 설정이 적용된다." 라고 이야기 했지만 정확히는 아래의 2가지 조건을 만족해야 기본 보안 설정이 자동으로 적용된다.

  1. SecurityFilterChain 클래스와 HttpSecurity 클래스가 ClassPath 에 위치한 경우
  2. SecurityFilterChain 이 Bean 으로 등록되지 않은 경우

정리하면 (1) 의 경우는 항상 만족한다고 보면된다. Spring Security 프레임워크를 가져다 사용하기 때문에 SecurityFilterChain 과 HttpSecurity 클래스는 ClassPath 에 존재한다. 하지만 지정된 ClassPath 를 변경하거나 둘 중 하나의 클래스를 주석처리 및 삭제하는 경우 해당 조건을 만족 못할 수도 있다. 결국 두 클래스를 따로 개발자가 건들지 않는 이상은 항상 만족하는 거라 이해했다.

 

(2) 의 경우는 개발자가 직접 정의한 보안 설정(SecurityConfiguration)을 통해 SecurityFilterChain 이 Bean 에 등록된 경우 만족하지 않게 된다. 그러면 기본 보안 설정이 OFF 되고 개발자가 정의한 보안 설정만이 적용되는 것이다. 물론 개발자가 별도의 보안 설정을 정의하지 않았다면 만족하게 된다.

 

위의 내용은 SpringBootWebSecurityConfiguration.SecurityFilterChainConfiguration 클래스의 defaultSecurityFilterChain() 에 지정된 @ConditionalOnDefaultWebSecurity → @Conditional 에 지정된 DefaultWebSecurityCondition 클래스를 통해 알 수 있었다.

DefaultWebSecurityCondition 클래스

 

 

1. SecurityConfiguration 정의

 그렇다면 보안 설정은 어떻게 정의하면 될까? 답은 가까이에 있다. 바로 이 때까지 자동으로 사용하였던 SpringBootWebSecurityConfiguration.SecurityFilterChainConfiguration 클래스와 유사하게 직접 보안 설정 클래스를 작성해주면 된다.

@Configuration
@EnableWebSecurity    // 정의한 보안 설정 클래스를 Spring Security 에서 사용할 때 지정하는 어노테이션
public class SecurityConfiguration {
    @Bean
    public SecurityFilterChain createSecurityFilterChain(HttpSecurity http) throws Exception {
        return http
                .authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
                .formLogin(Customizer.withDefaults())
                .build();
    }
}

 

많은 것을 설정하지 않았다. 먼저 해당 설정 클래스에 @Configuration 은 물론 @EnableWebSecurity 도 지정해주었다. @EnableWebSecurity 에 대한 설명은 아래와 같다.

Add this annotation to an @Configuration class to have the Spring Security configuration defined in any WebSecurityConfigurer or more likely by exposing a SecurityFilterChain bean.

WebSecurityConfigurer 에 Spring Security 구성을 정의하거나 Security Filter Chain - Bean 을 노출하여 정의하려면 @Configuration 이 지정된 클래스에 해당 주석을 추가하세요.

 

확실하지는 않지만 정의한 보안 설정을 Bean 으로 등록해 Spring Security 에서 사용하기 위해 @EnableWebSecurity 를 사용하라는 내용으로 이해하였다.

 

그리고 HttpSecurity 에 보안 설정을 추가하는 것은 이후의 강의에서 더 자세히 다룰 것이기에 기본적으로 모든 요청에 대해 인증 절차를 거쳐야 한다는 설정기본 로그인 방식을 사용한다는 설정을 추가하였다.

 

이후 디버깅을 통해 defaultSecurityFilterChain() 이 아닌 createSecurityFilterChain() 에 지정한 브레이크 포인트가 걸리는 것을 확인했다. 앞서 말한대로 정의한 보안 설정이 있기 때문에 기본 보안 설정이 수행(적용)되지 않은 것이다.

 

 

2. 사용자 설정

 또 한 번 되짚어 보자면 현재 Spring Security 에 사용되는 하나의 계정을 자동적으로 생성해주고 있다. 이 작업을 직접하기 위해서는 어떤 방법이 있을까?

2-1. application.yml 사용

 먼저 application.yml(또는 properties) 에 사용할 계정을 작성하는 방법이 있다.

spring:
  security:
    user:
      name: user
      password: "!testPW24"
      roles: USER

사용자 설정시 실행창 상태

 

설정후 애플리케이션을 실행하니 실행창이 좀 달라졌다. 분명 이전에는 자동으로 생성된 계정에 대한 패스워드(UUID)가 실행창에 출력되었는데 이번에는 출력되지 않았다. 이로인해 계정을 자동으로 생성하는 것도 보안설정과 마찬가지로 설정한 사용자 정보가 있다면 자동으로 생성하지 않는 다는 것을 확인할 수 있었다.

 

application.yml 에 작성한 사용자 정보로 로그인을 시도하니 인증을 통과해 API 요청("/") 이 수행되어 웹 브라우저에 "home" 이 출력되는 것을 확인할 수 있었다. 참고로 "home" 이 출력되는 것은 이전에 보안 절차를 통과해 수행될 요청에 해당 문자열이 출력되도록 Controller 를 임시로 만들어 두었기 때문이다.

 

2-2. 설정 클래스 사용

 두 번째로는 설정 클래스(@Configuration 지정 클래스)에 직접 정의하는 방법이 있다.

@Configuration
@EnableWebSecurity
public class SecurityConfiguration {
    ...

    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails user1 = User.withUsername("user")
                .password("{noop}1111")
                .roles("USER")
                .build();
        UserDetails user2 = User.withUsername("user2")
                .password("{noop}2222")
                .roles("USER")
                .build();

        return new InMemoryUserDetailsManager(user1, user2);
    }
}

 

물론 해당 방식도 사용자를 설정했기에 자동으로 계정을 생성하지 않아 실행창에 생성된 계정의 패스워드가 출력되지 않는다. 여기서 특이사항은 잘 보면 'user' 변수의 Username 이 application 에 설정한 사용자 계정과 동일한데 실행 후 로그인을 시도하면 설정 클래스에 설정한 사용자의 정보는 로그인을 통과하지만 application.yml 에 설정한 사용자 정보는 통과하지 못한다. 그 이유는 우선순위가 설정 클래스에 지정한 사용자 정보가 application.yml 에 지정한 사용자 정보보다 높기 때문이다(참고로 현재 application.yml 에 지정한 사용자 정보는 주석처리가 되어있지 않다 = 함께 사용 중이다).

 

 

3. 정리

 이렇게 보안 설정을 정의하는 방식사용자(계정)를 설정하는 방식에 대해 알아보았다. 하지만 보안 설정 정의의 경우 거의 필수적으로 활용하겠지만 사용자를 설정하는 것은 당장에 사용하지 않을 것 같다. 그 이유는 앞으로 반필수 적으로 DB 를 사용하게 될테고, 그러면 사용자 정보를 DB 에 저장할 것이기 때문이다.

 

그러니 "아 이런 방식으로 사용자(계정) 정보를 추가할 수 있구나!" 정도로만 이해하고 이후에 DB 를 통한 사용자 인증/인가 방식에 대해 더 집중해 학습해볼 생각이다.


참고 강의/문서