JWT ๊ธฐ๋ฐ˜์˜ ์ธ์ฆ์„ ๊ตฌ์„ฑํ•œ ํ”„๋กœ์ ํŠธ์—์„œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์— ๋Œ€ํ•œ ์‚ฌ์šฉ์ž๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด์„œ WithSecurityContext ์™€ WithSecurityContextFactory ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ฐ€์ƒ์˜ ์‚ฌ์šฉ์ž์™€ ํ† ํฐ์„ ๋ฐœ๊ธ‰ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด ๋˜๋Š” ๊ฒƒ์œผ๋กœ ์•Œ๋ ค์ ธ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ, ์‹ ๊ทœ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ๋‹จ์ผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์•„๋‹Œ ์ธ์ฆ์˜ ๊ธฐ๋ฐ˜์ด ๋˜๋Š” ์™ธ๋ถ€ ํ”Œ๋žซํผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์š”์ฒญํ•˜์—ฌ ์ธ์ฆ์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ๊ถŒํ•œ์„ ์ฒ˜๋ฆฌํ•˜๋„๋ก ๋กœ์ง์„ ๊ตฌ์„ฑํ•˜์—ฌ ๋‹จ์ˆœํžˆ ๊ฐ€์ƒ์˜ ์‚ฌ์šฉ์ž๊ฐ€ ์•„๋‹Œ ์‹ค์ œ๋กœ ์กด์žฌํ•˜๋Š” ์‚ฌ์šฉ์ž๋กœ ์ธ์ฆํ•  ์ˆ˜ ์žˆ๋Š” ์ปจํ…์ŠคํŠธ๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ–ˆ๋‹ค. ์‚ฌ์šฉ์ž ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•œ ์ปจํ…์ŠคํŠธ๋ฅผ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ–ˆ๋‹ค.

WithMockUser
@Retention(RetentionPolicy.RUNTIME) @WithSecurityContext(factory = WithMockUserSecurityContextFactory.class) public @interface WithMockUser { String id() default "kdevkr@gmail.com"; }
WithMockUserSecurityContextFactory
@RequiredArgsConstructor @Component public class WithMockUserSecurityContextFactory implements WithSecurityContextFactory<WithMockUser> { private final JwtTokenProvider jwtTokenProvider; @Override public SecurityContext createSecurityContext(WithMockUser mockUser) { SecurityContext context = SecurityContextHolder.createEmptyContext() Optional<User> optionalUser = getUserById(mockUser.id()); if (optionalUser.isPresent()) { User user = optionalUser.get(); Optional<JwtToken> token = getToken(user); if (token.isPresent()) { String accessToken = token.get().getAccessToken(); Authentication authentication = jwtTokenProvider.getAuthentication(accessToken); context.setAuthentication(authentication); } } return context; } }

No thread-bound request found

java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.

์„œ๋น„์Šค ๋ ˆ์ด์–ด์˜ ํด๋ž˜์Šค์—์„œ ์š”์ฒญ ์Šค๋ ˆ๋“œ์—์„œ ํ† ํฐ ์ •๋ณด๋ฅผ ์กฐํšŒํ•˜๊ธฐ ์œ„ํ•ด RequestContextHolder ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ˜„์žฌ ์š”์ฒญ์— ๋Œ€ํ•œ Authorization ํ—ค๋”๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋กœ์ง์œผ๋กœ ์ธํ•ด ๋ฐœ์ƒํ•œ ๋ฌธ์ œ๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค. ์„œ๋น„์Šค ๋ ˆ๋ฒจ์˜ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์—์„œ๋Š” ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ํ†ตํ•œ ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•œ ์Šค๋ ˆ๋“œ๊ฐ€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ๋ณธ์ ์œผ๋กœ๋Š” ์กฐํšŒํ•  ์ˆ˜ ์—†๋‹ค. ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€์— ํฌํ•จ๋œ RequestContextListener ๊ฐ€ ํ•ด๊ฒฐ๋ฐฉ์•ˆ์ด ๋  ์ˆ˜ ์žˆ๋‹ค. RequestContextListenerTests.java ๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ RequestContextListener ํด๋ž˜์Šค๋ฅผ ํ†ตํ•ด ์š”์ฒญ์— ๋Œ€ํ•œ ์Šค๋ ˆ๋“œ๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Œ์„ ํ™•์ธํ–ˆ์œผ๋ฉฐ MockHttpServletRequest๋ฅผ ํ†ตํ•ด ServletRequestAttributes๋ฅผ RequestContextHolder์˜ ์Šค๋ ˆ๋“œ ๋กœ์ปฌ์— ๋ฐ˜์˜๋˜๊ฒŒ ํ•˜์—ฌ ์ปจํŠธ๋กค๋Ÿฌ ๋ ˆ๋ฒจ์ด ์•„๋‹Œ ์„œ๋น„์Šค ๋ ˆ๋ฒจ์—์„œ๋„ ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž ๊ธฐ๋ฐ˜์˜ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜์˜€๋‹ค.

WithMockUserSecurityContextFactory
@RequiredArgsConstructor @Component public class WithMockUserSecurityContextFactory implements WithSecurityContextFactory<WithMockUser> { private final JwtTokenProvider jwtTokenProvider; @Override public SecurityContext createSecurityContext(WithMockUser mockUser) { SecurityContext context = SecurityContextHolder.createEmptyContext(); RequestContextListener listener = new RequestContextListener(); MockServletContext servletContext = new MockServletContext(); MockHttpServletRequest request = new MockHttpServletRequest(servletContext); listener.requestInitialized(new ServletRequestEvent(servletContext, request)); Optional<User> optionalUser = getUserById(mockUser.id()); if (optionalUser.isPresent()) { User user = optionalUser.get(); Optional<JwtToken> token = getToken(user); if (token.isPresent()) { String accessToken = token.get().getAccessToken(); Authentication authentication = jwtTokenProvider.getAuthentication(accessToken); context.setAuthentication(authentication); request.addHeader(HttpHeaders.AUTHORIZATION, "Bearer %s".formatted(accessToken)); ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request); RequestContextHolder.setRequestAttributes(requestAttributes, true); } } return context; } }

์ฐธ๊ณ  ๋งํฌ