반응형
1. 문제
Spring Security + OAuth2를 사용해 JWT Token 기반 로그인을 구현한 경우, @WithMockUser를 사용해 Autenticated Rest API에 접근시 TokenAuthenticationFilter에서 error가 발생한다.
@WithMockUser(username="USER_NAME")
@Test
@WithMockUser(username = "USER_NAME")
public void user_me_유저정보조회_성공() throws Exception {
// given
UserPrincipal userPrincipal = UserPrincipal.create(user);
// when
mvc.perform(
get("/user/me")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(new Gson().toJson(userPrincipal)))
.andDo(print())
.andExpect(status().isOk());
}
2. 원인
@WithMockUser는 아래와 같이 username/password 정보만을 가지고 있기 때문에, TokenAuthenticaiton Filter에서 필요한 id 값이 들어있지 않다.
@WithMockUser
public @interface WithMockUser {
String value() default "user";
String username() default "";
String[] roles() default { "USER" };
String[] authorities() default {};
String password() default "password";
}
TokenAuthenticationFilter doFilterInternal(HttpServletRequest, HttpServletResponse, FilterChain)
try {
String jwt = getJwtFromRequest(request);
if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) {
Long userId = tokenProvider.getUserIdFromToken(jwt);
UserDetails userDetails = customUserDetailsService.loadUserById(userId);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (Exception ex) {
logger.error("Could not set user authentication in security context", ex);
}
filterChain.doFilter(request, response);
현재 내가 구현해놓은 JWT Token은 Authenticated Rest API에 접근시, JWT Token에서 id를 decode해 UserDetail 정보를 load 하고있다.
3. 해결
MockMvc에 UserDetail을 전달한다. 이때 UserDetail은 @SpringBootTest의 setup( )에서 저장한 테스트용 User를 사용하면 된다.
MockMvc.with(user(UserDetail))
@Before
public void setup(){
// mvc
mvc = MockMvcBuilders
.webAppContextSetup(context)
.apply(springSecurity())
.build();
// save user
user = userRepository.save(UserSetup.builder().build().get());
}
@Test
public void user_me_유저정보조회_성공() throws Exception {
// given
UserPrincipal userPrincipal = UserPrincipal.create(user);
// when
mvc.perform(
get("/user/me")
.with(user(userPrincipal)))
.andDo(print())
.andExpect(status().isOk());
}
위의 UserPrincipal은 UserDetail을 implements한 custom 구현체이다.
UserPrincipal
public class UserPrincipal implements OAuth2User, UserDetails {
...
}
반응형