스프링 시큐리티
나는 스프링 시큐리티가 너무 싫다.
공부하면서 느낀건 편한것도 많지만 간단한 JWT 정도 적용하는데는 굳이 써야하나? 라는 생각이다.
우선 변경되는 부분이 많아서 전에 썼던 프로젝트 코드를 다시 쓰려면 deprecated 된게 한가득이다.
그렇다보니 바꿀 부분이 많아져서 스프링의 장점인 레퍼런스가 많다는 장점이 퇴색된다.
또 스프링 시큐리티라는 컨텍스트에 너무 의존적이라고 생각한다.
그래서 이걸 쓰려면 내부 구현을 속속들이 알아야 의도치 않은 결과를 만나지 않는다.
로그인을 FormData 형식으로 받아서 Json으로 로그인을 하려면 따로 필터를 만들어야 하는것도 불편하다.
복잡한 과정들을 추상화해서 쓰기 편하게 만들었단건 알겠지만 덕분에 공부해야할거도 꽤 있고 복잡하다.
여러데서 쓴다니까 공부는 해둬야지 별 수 있나 싶긴 하지만 그래도 싫은건 싫다.
시큐리티 환경에서 컨트롤러 테스트
무엇보다 내가 싫은건 시큐리티 환경에서 테스트 코드를 작성하기가 너무 번거롭다는 것이다.
아마 지금의 내 JWT 필터 로직이 스프링 시큐리티 컨텍스트와 따로 노는게 문제라고 생각은 하지만,
도무지 시큐리티 컨텍스트 내에 내 JWT 필터 로직을 넣는 방법을 모르겠다.
Argument Resolver로 JWT 기능을 구현했으면 진작 끝냈을것 같다.
이전 JWT 필터 글에서 썼던 대로 기본적으로 모든 요청에 대해 JWT를 검사한다.
따라서 컨트롤러 테스트를 할 때도 이 필터를 거쳐야하기 때문에 JWT를 안넣어주면 필터단에서 걸러진다.
이걸 어떻게 처리해야 하는지 고민하다가 시행착오 끝에 결국 테스트용 SecurityConfig를 만들기로 했다.
1. 구현
TestSecurityConfig
프로덕션 코드에서 검색되지 않도록 테스트 디렉토리에 아래처럼 테스트용 SecurityConfig를 작성한다.
@TestConfiguration
@EnableWebSecurity
@RequiredArgsConstructor
public class TestSecurityConfig {
private final ObjectMapper objectMapper;
private final UserDetailsService userDetailsService;
private final JwtUtils jwtUtils;
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return web -> web.ignoring()
.requestMatchers("/favicon.ico")
.requestMatchers("/error")
.requestMatchers(toH2Console());
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.sessionManagement(session -> session.sessionCreationPolicy(STATELESS))
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/**").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(jsonAuthFilter(), UsernamePasswordAuthenticationFilter.class)
.exceptionHandling(e -> {
e.authenticationEntryPoint(new Http401Handler(objectMapper));
e.accessDeniedHandler(new Http403Handler(objectMapper));
})
.csrf(AbstractHttpConfigurer::disable)
.build();
}
@Bean
public JsonAuthFilter jsonAuthFilter() {
JsonAuthFilter filter = new JsonAuthFilter("/api/auth/login", objectMapper);
filter.setAuthenticationManager(authenticationManager());
filter.setAuthenticationSuccessHandler(new LoginSuccessHandler(objectMapper, jwtUtils));
filter.setAuthenticationFailureHandler(new LoginFailHandler(objectMapper));
return filter;
}
@Bean
public AuthenticationManager authenticationManager() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
provider.setPasswordEncoder(passwordEncoder());
return new ProviderManager(provider);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new SCryptPasswordEncoder(
16,
8,
1,
32,
64
);
}
}
SecurityConfig
기존 SecurityConfig에 아래처럼 @Profile 애노테이션을 이용해 특정 프로필에서 사용하지 못하게 설정한다.
본인은 test 프로필에서 사용하지 못하게 했다.
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
@Profile("!test")
public class SecurityConfig {
2. 사용하기
1. 테스트용 config를 Import 및 @ActiveProfiles 설정
테스트 클래스에 아래 스크린샷처럼 @Import(TestSecurityConfig.class), @ActiveProfiles("test") 를 붙여준다.
2. 인증 필요한 테스트에 커스텀 @MockUser 애노테이션 적용
아래처럼 커스텀@MockUser 애노테이션을 적용한다.
'백엔드 > Spring Security' 카테고리의 다른 글
비로그인 사용자의 권한 처리: 메서드 시큐리티 적용 (0) | 2024.05.14 |
---|---|
시큐리티 환경에서 테스트 1: @WithMockUser 커스텀 (0) | 2024.04.24 |
JwtFilter 만들기 (0) | 2024.04.16 |