뭐라도 끄적이는 BLOG

Security Configuration 본문

SpringFramework/Spring Security

Security Configuration

Drawhale 2023. 7. 7. 18:42

Security Configuration

Spring Boot 3.0.0 이후 설정되는 Spring Security는 이전에 Configuration을 적용했던 방식과는 조금 달라졌다. 이전에는 WebSecurityConfigurerAdapter가 @Configuration이 설정된 Class에 상속됬어야 했는데 지금은 @EnableWebSecurity를 추가해주면 된다.

 

Spring Security without the WebSecurityConfigurerAdapter

In Spring Security 5.7.0-M2 we deprecated the WebSecurityConfigurerAdapter, as we encourage users to move towards a component-based security configuration. To assist with the transition to this new style of configuration, we have compiled a list of common

spring.io

Configuration 설정 체험

이전 포스팅에서 만든 HelloController에서 테스트를 위한 다른 메소드들을 추가해주었다.

@RestController
public class HomeController {
    @GetMapping("/")
    public String home() {
        return "Welcome home";
    }

    @GetMapping("/user")
    public String user(Authentication authentication) {
        return String.format("<h1>Welcome %s !</h1>", authentication.getName());
    }

    @GetMapping("/admin")
    public String admin(Authentication authentication) {
        return String.format("<h1>Welcome %s !</h1>", authentication.getName());
    }
}

이제 SecurityConfiguration을 설정할 클래스를 하나 생성한뒤 간단한 설정정보를 입력해보자

경로는 ComponentScan이 가능한 경로 어디든 괜찮지만 보통 config 패키지 아래에 생성한다.

@Configuration
@EnableWebSecurity
public class SecurityConfiguration {
    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests(authorize -> {
                    authorize.requestMatchers("/").permitAll();
                    authorize.requestMatchers("/user/**").authenticated();
                    authorize.requestMatchers("/admin/**").denyAll();
                })
                .formLogin(Customizer.withDefaults())
                .httpBasic(Customizer.withDefaults());
        return http.build();
    }
}

Http Request중 URL에 /에 매칭된 요청은 모두 허용(permitAll())하고 /user이하는 인증(authenticated())을해야하며 /admin이하는 모두 거부하는 규칙을 설정하였다.

각각의 URL에 직접 접근해보면 /는 그냥 들어가지고 /user에서 로그인 화면으로 리다이렉션 되는 것을 볼수 있다. 그리고 /admin은 HTTP403응답이 오는것을 확인할 수 있다.

authorizeHttpRequests에서 각 경로에 대한 인증 여부를 결정할 수 있다는 것을 확인해 볼 수 있다. 이후 각 사용자의 역할(ROLE)에 따라 접근 여부를 결정하는 방법도 확인해볼 것이다.

※참고: Spring Security의 기본 상태 유지 방식 확인

postman으로 로그인 했을때 Session Cookie가 전송되는 것을 확인할 수 있다.

UserDetailsService로 인증 가능한 user 생성

이전 포스팅에 application.yaml에 설정한 user name과 password를 삭제하고 코드에서 직접 user를 생성해 볼 것이다. 

spring:
  security:
    user:
      name: member
      password: member

User를 코드에서 생성하면서 역할(Role)에대한 테스트도 같이 진행해본다.

@Configuration
@EnableWebSecurity
public class SecurityConfiguration {
    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests(authorize -> {
                    authorize.requestMatchers(HttpMethod.GET, "/").permitAll();
                    authorize.requestMatchers(HttpMethod.GET, "/user/**").hasRole("USER");
                    authorize.requestMatchers(HttpMethod.GET, "/admin/**").hasRole("ADMIN");
                    authorize.anyRequest().authenticated();
                })
                .formLogin(withDefaults())
                .httpBasic(withDefaults());
        return http.build();
    }

    @Bean
    UserDetailsService userDetailsService() {
        UserDetails admin = User.builder()
                .username("admin")
                .password("{noop}admin")
                .roles("USER", "ADMIN")
                .build();
        UserDetails user = User.builder()
                .username("member")
                .password("{noop}member")
                .roles("USER")
                .build();
        return new InMemoryUserDetailsManager(admin, user);
    }
}

/user에는 USER Role이 접근할 수 있도록 설정하고 /admin에는 ADMIN Role이 접근할 수 있도록 설정을 변경해 주었다. 그리고 아래 UserDetailsService에 admin과 member를 만들어 권한을 주고 생성하였다.

UserDetailsService는 사용자 인증을 정의하는 부분이다. 지금은 간단히 메모리에 사용자 정보를 저장하여 인증에 사용하지만 이후 해당 부분에서 데이터베이스 등을 통해 인증을 구현하게 된다.

이제 /user는 member와 admin 모두 접속할 수 있지만 /admin은 admin 사용자만 접근 가능하다는 것을 확인해 볼 수 있다.

password부분의 noop는 비밀번호 해싱 방식을 나타낸다. noop는 해싱을 하지 않은 평문을 나타낼때 사용한다.

반응형