[security] JwtFilter 추가하고 테스트 (authentication 주입)

Coastby·2022년 12월 22일
0

문제 해결

목록 보기
16/17
post-custom-banner

🚫 문제 상황

SpringSecurity를 적용하면 컨트롤러 테스트에서도 인증이 필요하다. 이 때 가짜 사용자로 테스트를 실행할 수 있는 방법이 @WithMockUser이다. MockUser는 아래와 같은 속성을 가진 MockUser를 만들고 WithSecurityContextFactory 에서 이를 이용해 Authentication의 principal에 넣는다.

public @interface WithMockUser {
	String value() default "user";
	String username() default "";
	String[] roles() default { "USER" };
	String[] authorities() default {};
	String password() default "password";
}

그러나 Jwt 또는 OAuth 등을 이용하여 커스텀 필터를 만든 경우 Authentication에 넣는 값도 달라진다. 이번 프로젝트 경우는 jwt과 Authentication의 principal에 userName을 넣었는데 이 값은 위의 MockUser에서 제공하지 않는다.
바로 @WithMockUser로 테스트를 진행했더니 아래와 같은 에러가 발생하였다.

⭕️ 해결

해결방법은 MockUser를 커스텀해서 테스트에 주입해준다.
@WithMockUser와 함께 진행되는 SecurityContext가 아닌 직접 만든 SecurityContext원하는 MockUser의 Authentication을 넣어서 테스트를 진행할 수 있다.

  1. @WithMockCustomUser 어노테이션을 만든다.
    : 가짜 사용자를 만든다.
    WithMockCustomUser에는 @WithSecurityContext 어노테이션이 선언되어 있다. 값으로 주어진 factory를 이용하여 SecurityContext를 생성해서 테스트를 실행하라는 신호이다.

    @Retention(RetentionPolicy.RUNTIME)
    @WithSecurityContext(factory = WithMockCustomUserSecurityContextFactory.class)
    public @interface WithMockCustomUser {
      String userName() default "user";
      String role() default "USER";
    
    	}
  2. WithMockCustomUserSecurityContextFactory
    로직에서 token을 발급할 때와 비슷하게 구현하였다.

    public class WithMockCustomUserSecurityContextFactory implements WithSecurityContextFactory<WithMockCustomUser> {
      @Override
      public SecurityContext createSecurityContext(WithMockCustomUser annotation) {
          final SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
    
          final UsernamePasswordAuthenticationToken authenticationToken
                  = new UsernamePasswordAuthenticationToken(annotation.userName(), null,
                  List.of(new SimpleGrantedAuthority(annotation.role())));
          securityContext.setAuthentication(authenticationToken);
          return securityContext;
      }
    }
  3. 테스트에 @WithMockCustomUser를 달아준다.

      @Test
      @DisplayName("포스트 작성 성공")
      @WithMockCustomUser
      void post_add_success() throws Exception {
          given(postService.add(postAddRequest, "user")).willReturn(new PostWorkResponse("포스트 등록 완료", 0));
    
          mockMvc.perform(
                  post("/api/v1/posts")
                  ...
     }

참고 :
https://godekdls.github.io/Spring%20Security/testing/
https://jiwondev.tistory.com/270

profile
훈이야 화이팅
post-custom-banner

0개의 댓글