[Spring][Security] 스프링 시큐리티 테스트

최대 1 분 소요

들어가며

MockUser를 이용하여 메소드 보안 단위 테스트 하는 방법과 과정을 기록하기 위한 포스팅

@WithSecurityContext

@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@WithSecurityContext(factory = WithMockCustomUserSecurityContextFactory.class)
public @interface WithMockCustomUser {

    String username() default "yhw";

    String studentId() default "~";

    String password() default "~";

    String passwordConfirm() default "~";

    String role() default "ROLE_USER";
}

WithMockCustomUserSecurityContextFactory

  • WithMockCustomUser를 매개변수로 받아서 애노테이션의 값을 이용해 SecurityContext를 반환하다. SecurityContext에는 Authentication이 담겨 있다. 스프링이 기본으로 제공하는 @WithMockUser, @WithAnonyMous 등도 이와 같은 방법으로 구성되어 있다.
public class WithMockCustomUserSecurityContextFactory implements WithSecurityContextFactory<WithMockCustomUser> {
    @Override
    public SecurityContext createSecurityContext(WithMockCustomUser annotation) {
        SecurityContext context = SecurityContextHolder.createEmptyContext();
        User user = new User(new SignUpDTO(annotation.username(), annotation.studentId(), annotation.password(),
                annotation.passwordConfirm()), new BCryptPasswordEncoder());

        UserContext userContext = new UserContext(user);
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
                new UsernamePasswordAuthenticationToken(userContext, null, List.of(new SimpleGrantedAuthority(annotation.role())));

        context.setAuthentication(usernamePasswordAuthenticationToken);

        return context;
    }
}

사용법

@WebMvcTest(AuthController.class)
@Import({ObjectMapper.class, JwtAuthenticationEntryPoint.class, HttpEncodingAutoConfiguration.class})
class AuthControllerTest {

    @Autowired
    MockMvc mockMvc;

    @Autowired
    ObjectMapper objectMapper;

    @MockBean
    AuthService authService;

    @MockBean
    TokenProvider tokenProvider;

    @MockBean
    private JwtAccessDeniedHandler jwtAccessDeniedHandler;

    @Test
    @DisplayName("withdrawalFailTest")
    @WithMockCustomUser(studentId = "1234")
    public void withdrawalFailTest() throws Exception {
        mockMvc.perform(post("/api/authentication/withdrawal/{studentId}", "123"))
                .andExpect(status().isForbidden())
                .andExpect(result -> assertThat(result.getResolvedException()).isInstanceOf(AccessDeniedException.class))
                .andDo(print());
    }

    @DisplayName("withdrawalSuccessTest")
    @WithMockCustomUser(studentId = "1234")
    public void withdrawalSuccessTest() throws Exception {
        mockMvc.perform(post("/api/authentication/withdrawal/{studentId}", "1234"))
                .andExpect(status().isOk())
                .andDo(print());
    }
}

댓글남기기