@WithMockUser

스프링 시큐리티를 사용하면 시큐리티 컨텍스트에서 Principal 정보를 꺼내 쓸 수 있다.

따라서 인증 완료된 유저는 컨트롤러에서 @AuthenticationPrincipal 을 사용하여 사용자 정보를 이용하곤 한다.

하지만 컨트롤러 테스트를 할 때 컨트롤러를 호출하면 인증을 하지 않았기 때문에 UserPrincipal 객체가 null일 것이다.

당연히 실제 환경처럼 컨트롤러 호출 시 쿠키에 Jwt를 넣는 등의 인증 과정을 거치면 되겠지만,

매 테스트마다 유효한 Jwt를 만들어서 넣어줘야한다는 문제가 생긴다.

유저 정보를 DB에 넣고, 유저 정보로 Jwt를 만들고, 요청에 넣어주는건 굉장히 번거롭다.

 

이런 번거로움을 해소하기 위해 스프링 시큐리티에서는 @WithMockUser 라는 애노테이션을 제공한다.

이를 이용하면 시큐리티 컨텍스트에 MockUser 정보를 넣어두기 때문에 인증 없이 컨트롤러를 호출해도 문제없이 사용할 수 있다.

하지만 서비스마다 유저 객체 정보가 다르기 때문에 기본적인 @WithMockUser 를 사용하기에는 한계가 있다.

따라서 이번 글에서는 @WithMockUser 를 커스텀해서 사용하여 서비스에 맞는 MockUser 정보를 이용해볼 것이다.


1. 구현

CustomMockSecurityContext

MockSecurityContext를 만든다.

아래처럼 WithSecurityContextFactory를 구현하고, 시큐리티 컨텍스트에 MockUser 정보를 넣어준다.

@RequiredArgsConstructor
public class PawLandMockSecurityContext implements WithSecurityContextFactory<PawLandMockUser> {

    private final UserRepository userRepository;

    @Override
    public SecurityContext createSecurityContext(PawLandMockUser annotation) {
        User user = User.builder()
            .email(annotation.email())
            .nickname(annotation.nickname())
            .password(annotation.password())
            .type(annotation.type())
            .profileImage(annotation.profileImage())
            .introduce(annotation.getIntroduce())
            .build();
        userRepository.save(user);

        UserPrincipal userPrincipal = new UserPrincipal(user);
        SimpleGrantedAuthority role = new SimpleGrantedAuthority(annotation.role());
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userPrincipal,
            user.getPassword(),
            List.of(role));

        SecurityContext context = SecurityContextHolder.createEmptyContext();
        context.setAuthentication(authenticationToken);
        return context;
    }
}

CustomMockUser

이제 위에서 만든 Mock 시큐리티 컨텍스트를 사용할 커스텀 MockUser 애노테이션을 만든다.

아래처럼 원하는 필드를 설정하고, 기본 값을 정해주면 애노테이션을 붙이면 설정한 MockUser 정보를 이용한다.

@Retention(RetentionPolicy.RUNTIME)
@WithSecurityContext(factory = PawLandMockSecurityContext.class)
public @interface PawLandMockUser {

    String email() default "midcondria@naver.com";

    String nickname() default "나는짱";

    String password() default "asd123123";

    String profileImage() default "";

    String getIntroduce() default "";

    LoginType type() default LoginType.NORMAL;

    String role() default "ROLE_USER";

}

2. 사용하기

1. 애노테이션만 붙일 때

아래처럼 애노테이션만 붙이면 기본 값으로 설정한 정보를 사용한다.

2. 애노테이션에 원하는 값을 넣을 수 있음

아래처럼 애노테이션에 원하는 값을 넣으면 원하는 설정한 정보를 사용할 수 있다.

+ Recent posts