์คํ๋ง ์ํ๋ฆฌํฐ JWT ์ฌ์ฉ์ ํ ์คํธ
JWT ๊ธฐ๋ฐ์ ์ธ์ฆ์ ๊ตฌ์ฑํ ํ๋ก์ ํธ์์ ํ
์คํธ ์ฝ๋์ ๋ํ ์ฌ์ฉ์๋ฅผ ๋ง๋ค๊ธฐ ์ํด์ WithSecurityContext
์ WithSecurityContextFactory
๋ฅผ ์ฌ์ฉํด์ ๊ฐ์์ ์ฌ์ฉ์์ ํ ํฐ์ ๋ฐ๊ธํ๋ ์ฝ๋๋ฅผ ๊ตฌํํ๋ฉด ๋๋ ๊ฒ์ผ๋ก ์๋ ค์ ธ ์๋ค. ํ์ง๋ง, ์ ๊ท ํ๋ก์ ํธ์์๋ ๋จ์ผ ์ ํ๋ฆฌ์ผ์ด์
์ด ์๋ ์ธ์ฆ์ ๊ธฐ๋ฐ์ด ๋๋ ์ธ๋ถ ํ๋ซํผ ์ ํ๋ฆฌ์ผ์ด์
์ ์์ฒญํ์ฌ ์ธ์ฆ์ ์ํํ๊ณ ๊ถํ์ ์ฒ๋ฆฌํ๋๋ก ๋ก์ง์ ๊ตฌ์ฑํ์ฌ ๋จ์ํ ๊ฐ์์ ์ฌ์ฉ์๊ฐ ์๋ ์ค์ ๋ก ์กด์ฌํ๋ ์ฌ์ฉ์๋ก ์ธ์ฆํ ์ ์๋ ์ปจํ
์คํธ๋ฅผ ๋ง๋ค์ด์ผ ํ๋ค. ์ฌ์ฉ์ ํ
์คํธ๋ฅผ ์ํ ์ปจํ
์คํธ๋ฅผ ์ ์ฉํ๊ธฐ ์ํด ์๋์ ๊ฐ์ด ์์ฑํ๋ค.
@Retention(RetentionPolicy.RUNTIME)
@WithSecurityContext(factory = WithMockUserSecurityContextFactory.class)
public @interface WithMockUser {
String id() default "kdevkr@gmail.com";
}
@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์ ์ค๋ ๋ ๋ก์ปฌ์ ๋ฐ์๋๊ฒ ํ์ฌ ์ปจํธ๋กค๋ฌ ๋ ๋ฒจ์ด ์๋ ์๋น์ค ๋ ๋ฒจ์์๋ ์ธ์ฆ๋ ์ฌ์ฉ์ ๊ธฐ๋ฐ์ ํ
์คํธ๋ฅผ ์ํํ ์ ์๊ฒ ํ์๋ค.
@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;
}
}