Lv6. Config ๊ตฌ์กฐ ๊ฐ์ ๋ฐ ArgumentResolver Bean ๋ฑ๋ก ๋ฌธ์ ํด๊ฒฐ
1. ๋ฌธ์ ์ธ์ ๋ฐ ์ ์
Lv5์์ ๊ด๋ฆฌ์ API ๋ก๊น
๊ธฐ๋ฅ(Interceptor + AOP)์ ๊ตฌํํ๋ฉด์ WebConfig๋ฅผ ์์ ํ์๋ค.
์ด ๊ณผ์ ์์ AuthUserArgumentResolver๋ฅผ ์์ฑ์ ์ฃผ์
๋ฐฉ์์ผ๋ก ๊ด๋ฆฌํ๋๋ก ๊ตฌ์กฐ๋ฅผ ์ ๋ฆฌํ์๋ค.
๊ธฐ์กด ์ฝ๋์์๋ HandlerMethodArgumentResolver๋ฅผ ๋ฑ๋กํ ๋ ์๋์ฒ๋ผ ์ง์ ๊ฐ์ฒด๋ฅผ ์์ฑํ ์๋ ์์๋ค.
resolvers.add(new AuthUserArgumentResolver());
ํ์ง๋ง Config ๊ตฌ์กฐ๋ฅผ ์ ๋ฆฌํ๋ฉด์ ๋ค์๊ณผ ๊ฐ์ด ์์กด์ฑ ์ฃผ์ (DI) ๋ฐฉ์์ผ๋ก ๋ณ๊ฒฝํ์๋ค.
private final AuthUserArgumentResolver authUserArgumentResolver;
๊ทธ๋ฐ๋ฐ ์คํ ๊ณผ์ ์์ ๋ค์๊ณผ ๊ฐ์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค.
Could not autowire. No beans of 'AuthUserArgumentResolver' type found

์ฆ, WebConfig์์ AuthUserArgumentResolver๋ฅผ ์ฃผ์
๋ฐ์ผ๋ ค๊ณ ํ์ง๋ง
์คํ๋ง ์ปจํ
์ด๋์ ํด๋น ํด๋์ค๊ฐ Bean์ผ๋ก ๋ฑ๋ก๋์ด ์์ง ์์ ๊ฐ์ฒด๋ฅผ ์ฐพ์ง ๋ชปํ๋ ๋ฌธ์ ์๋ค.
์ด ๋ฌธ์ ์ ์์ธ์ ๋ค์๊ณผ ๊ฐ๋ค.
- AuthUserArgumentResolver๊ฐ ์คํ๋ง Bean์ผ๋ก ๋ฑ๋ก๋์ด ์์ง ์์
- WebMvcConfigurer์์ Resolver๋ฅผ ๋ฑ๋กํ๋ ค๋ฉด Bean ๋ฑ๋ก + Config ๋ฑ๋ก ๋ ๋จ๊ณ๊ฐ ํ์
๊ฒฐ๊ตญ Config ํด๋์ค์ Bean ๋ฑ๋ก ๊ตฌ์กฐ๋ฅผ ๋ช ํํ๊ฒ ์ ๋ฆฌํ ํ์๊ฐ ์์๋ค.
2. ํด๊ฒฐ ๋ฐฉ์
2-1. ์์ฌ๊ฒฐ์ ๊ณผ์
AuthUserArgumentResolver๋ฅผ ์คํ๋ง Bean์ผ๋ก ๋ฑ๋กํ๋ ๋ฐฉ๋ฒ์ ํฌ๊ฒ ๋ ๊ฐ์ง๊ฐ ์์๋ค.
๋ฐฉ๋ฒ 1. @Component๋ฅผ ์ฌ์ฉํ Bean ๋ฑ๋ก
@Component
public class AuthUserArgumentResolver implements HandlerMethodArgumentResolver
๋ฐฉ๋ฒ 2. @Configuration์์ @Bean์ผ๋ก ์ง์ ๋ฑ๋ก
@Bean
public AuthUserArgumentResolver authUserArgumentResolver() {
return new AuthUserArgumentResolver();
}
์ด๋ฒ ํ๋ก์ ํธ์์๋ ๋ฐฉ๋ฒ 1 (@Component)๋ฅผ ์ ํํ์๋ค.
์ ํ ์ด์ ๋ ๋ค์๊ณผ ๊ฐ๋ค.
- ArgumentResolver๋ ์ฌ๋ฌ ์ปจํธ๋กค๋ฌ์์ ์ฌ์ฌ์ฉ๋๋ ์ปดํฌ๋ํธ
- ์คํ๋ง์ด ์ง์ ๊ด๋ฆฌํ๋ Bean์ผ๋ก ๋ฑ๋กํ๋ ๊ฒ์ด ๊ตฌ์กฐ์ ์ผ๋ก ๋ ์์ฐ์ค๋ฌ์
- Config ํด๋์ค์ ์ฑ ์์ ์ต์ํํ ์ ์์
2-2. ํด๊ฒฐ ๊ณผ์
1) AuthUserArgumentResolver๋ฅผ Bean์ผ๋ก ๋ฑ๋ก
@Component
public class AuthUserArgumentResolver implements HandlerMethodArgumentResolver {
์ด๋ ๊ฒ ํ๋ฉด ์คํ๋ง ์ปจํ ์ด๋๊ฐ ์๋์ผ๋ก Bean์ผ๋ก ๋ฑ๋กํ๋ค.
2) WebConfig์์ ArgumentResolver ๋ฑ๋ก
@Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {
private final AuthUserArgumentResolver authUserArgumentResolver;
private final AdminApiInterceptor adminApiInterceptor;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(authUserArgumentResolver);
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(adminApiInterceptor)
.addPathPatterns("/admin/comments/*")
.addPathPatterns("/admin/users/*");
}
}
์ด ๊ณผ์ ์ ํตํด
- AuthUserArgumentResolver๋ ์คํ๋ง Bean
- WebConfig๋ Resolver๋ฅผ Spring MVC์ ๋ฑ๋กํ๋ ์ญํ
๋ก ์ฑ ์์ด ๋ช ํํ๊ฒ ๋ถ๋ฆฌ๋์๋ค.
3. ํด๊ฒฐ ์๋ฃ
3-1. ํ๊ณ
์ด๋ฒ ๋ฌธ์ ๋ฅผ ํตํด Spring MVC์ ArgumentResolver ๋์ ๊ตฌ์กฐ๋ฅผ ๋ช ํํ ์ดํดํ ์ ์์๋ค.
ํนํ ๋ค์ ๋ ๊ฐ์ง ํฌ์ธํธ๊ฐ ์ค์ํ๋ค.
1) ArgumentResolver๋ ์๋ ๋ฑ๋ก๋์ง ์๋๋ค
๋จ์ํ ํด๋์ค๋ฅผ ๋ง๋๋ ๊ฒ๋ง์ผ๋ก๋ ๋์ํ์ง ์๋๋ค.
๋ค์ ๋ ๋จ๊ณ๊ฐ ํ์ํ๋ค.
1. Bean ๋ฑ๋ก
2. WebMvcConfigurer.addArgumentResolvers ๋ฑ๋ก
2) Config ๊ตฌ์กฐ๊ฐ ๋ช ํํด์ผ ์ค๋ฅ๋ฅผ ์ค์ผ ์ ์๋ค
Config ํด๋์ค๊ฐ ์ฌ๋ฌ ๊ฐ๋ก ๋๋๊ฑฐ๋ Bean ๋ฑ๋ก์ด ๋๋ฝ๋๋ฉด
Could not autowire
No beans found
๊ฐ์ ์ค๋ฅ๊ฐ ์ฝ๊ฒ ๋ฐ์ํ๋ค.
์ด๋ฒ ๊ฒฝํ์ ํตํด
- ์คํ๋ง Bean ๋ฑ๋ก ๋ฐฉ์
- WebMvcConfigurer์ ์ญํ
- ArgumentResolver ๋์ ๋ฐฉ์
์ ์ค์ ์ค๋ฅ ํด๊ฒฐ ๊ณผ์ ์ ํตํด ์ดํดํ ์ ์์๋ค.
3-2. ์ ํ ๋ฐ์ดํฐ ๋น๊ต
ํญ๋ชฉ๊ฐ์ ์ ๊ฐ์ ํ
| Resolver ์์ฑ | new๋ก ์ง์ ์์ฑ ๊ฐ๋ฅ | ์คํ๋ง Bean์ผ๋ก ๊ด๋ฆฌ |
| Config ๊ตฌ์กฐ | Bean ๋ฑ๋ก ๋๋ฝ ๊ฐ๋ฅ | DI ๊ธฐ๋ฐ ๊ตฌ์กฐ |
| ์ค๋ฅ ๋ฐ์ | No beans found | ํด๊ฒฐ |
| ์ ์ง๋ณด์ | ์ค์ ์์น ๋ถ๋ช ํ | ์ญํ ๋ถ๋ฆฌ |
Lv6. JwtFilter์์ ์ธ์ฆ๊ณผ ์ธ๊ฐ ์ฑ ์ ๋ถ๋ฆฌ
1. ๋ฌธ์ ์ธ์ ๋ฐ ์ ์
ํ์ฌ JwtFilter๋ ์ธ์ฆ, ์ธ๊ฐ, ์ฌ์ฉ์ ์ ๋ณด ์ธํ , ์๋ฌ ์๋ต ์์ฑ๊น์ง ๋ชจ๋ ๋ด๋นํ๊ณ ์์๋ค.
ํ๋์ ํด๋์ค์ ๋๋ฌด ๋ง์ ์ฑ ์์ด ๋ชฐ๋ ค ์์ด ์ ์ง๋ณด์์ฑ๊ณผ ๊ฐ๋ ์ฑ์ด ๋จ์ด์ง๋ค๊ณ ํ๋จํ๋ค.
1. JWT ํ ํฐ ์กด์ฌ ์ฌ๋ถ ํ์ธ
2. JWT ์ ํจ์ฑ ๊ฒ์ฆ
3. Claims ์ถ์ถ ๋ฐ ์ฌ์ฉ์ ์ ๋ณด ์ ์ฅ
4. ๊ด๋ฆฌ์ ๊ถํ ๊ฒ์ฆ
5. ์๋ฌ ์๋ต ์์ฑ
์ฆ ํ๋์ ํด๋์ค๊ฐ ์ธ์ฆ ๊ณผ ์ธ๊ฐ ๊ทธ๋ฆฌ๊ณ ์์ธ ์ฒ๋ฆฌ๊น์ง ๋ด๋นํ๊ณ ์์๋ค.
- ํด๋์ค์ ์ฑ ์์ด ๊ณผ๋ํ๊ฒ ์ปค์ง
- ์ ์ง๋ณด์ ์ด๋ ค์
- ํ ์คํธ ์ด๋ ค์
- ์ฝ๋ ๊ฐ๋ ์ฑ ์ ํ
2. ํด๊ฒฐ ๋ฐฉ์
2-1. ์์ฌ๊ฒฐ์ ๊ณผ์
์ฒ์์๋ Filter๋ฅผ ์ธ์ฆ์ฉ/์ธ๊ฐ์ฉ ๋ ๊ฐ๋ก ๋ถ๋ฆฌํ๋ ๊ตฌ์กฐ๋ ๊ณ ๋ฏผํ๋ค.
ํ์ง๋ง ํ์ฌ ํ๋ก์ ํธ ๊ท๋ชจ์ ๊ณผ์ ๋ฒ์๋ฅผ ๊ณ ๋ คํ์ ๋, ๋จผ์ JwtFilter๋ฅผ ์๊ฒ ๋ง๋ค๊ณ JWT ์ฒ๋ฆฌ ๋ก์ง์ ๋ณ๋ helper๋ก ์์ํ๋ ๋ฐฉ์์ด ๊ฐ์ฅ ์ ์ ํ๋ค๊ณ ํ๋จํ๋ค.
๊ฐ ํด๋์ค์ ์ญํ ์ ๋ค์๊ณผ ๊ฐ๋ค.
ํด๋์ค์ญํ
| JwtFilter | ์์ฒญ ํํฐ๋ง |
| JwtValidator | JWT ๊ฒ์ฆ |
| JwtAuthorizationChecker | ๊ถํ ๊ฒ์ฌ |
2-2. ํด๊ฒฐ ๊ณผ์
JwtAuthHelper ํด๋์ค๋ฅผ ์์ฑํ๋ค.
claims ์ถ์ถ, request attribute ์ ์ฅ, admin ๊ถํ ์ฒดํฌ๋ฅผ JwtAuthHelper๋ก ์ด๋ํ๋ค.
JwtFilter๋ ์์ฒญ ํ๋ฆ ์ ์ด์ ์์ธ ์๋ต๋ง ๋ด๋นํ๋๋ก ์์ ํ๋ค.
@RequiredArgsConstructor
public class JwtAuthHelper {
private final JwtUtil jwtUtil;
public Claims validateAndExtractClaims(HttpServletRequest request) {
String bearerJwt = request.getHeader("Authorization");
if (bearerJwt == null) {
throw new IllegalArgumentException("์ธ์ฆ ํค๋๊ฐ ์์ต๋๋ค.");
}
String jwt = jwtUtil.substringToken(bearerJwt);
Claims claims = jwtUtil.extractClaims(jwt);
if (claims == null) {
throw new IllegalArgumentException("์ ํจํ์ง ์์ ํ ํฐ์
๋๋ค.");
}
return claims;
}
public void setUserAttributes(HttpServletRequest request, Claims claims) {
request.setAttribute("userId", Long.parseLong(claims.getSubject()));
request.setAttribute("email", claims.get("email"));
request.setAttribute("userRole", claims.get("userRole"));
}
public void validateAdminAccess(String url, Claims claims) {
UserRole userRole = UserRole.valueOf(claims.get("userRole", String.class));
if (url.startsWith("/admin") && !UserRole.ADMIN.equals(userRole)) {
throw new IllegalArgumentException("์ ๊ทผ ๊ถํ์ด ์์ต๋๋ค.");
}
}
}
3. ํด๊ฒฐ ์๋ฃ
3-1. ํ๊ณ
์ด๋ฒ ๋ฆฌํฉํ ๋ง์ ํตํด ์ธ์ฆ๊ณผ ์ธ๊ฐ๋ฅผ ์ฝ๋ ๊ตฌ์กฐ ์์์ ๋ถ๋ฆฌํด์ ์๊ฐํ๋ ์ฐ์ต์ ํ ์ ์์๋ค.
์์ ํ ๋ณ๋ Filter๋ก ๋ถ๋ฆฌํ์ง๋ ์์์ง๋ง, ์ต์ํ ํ๋์ ํด๋์ค๊ฐ ๋ชจ๋ ์ฑ ์์ ๊ฐ์ง๋ ๊ตฌ์กฐ๋ ๊ฐ์ ํ ์ ์์๋ค.
ํนํ ๋ค์ ๊ฐ๋ ์ ๋ช ํํ ์ดํดํ๊ฒ ๋์๋ค.
๊ฐ๋ ์ค๋ช
| ์ธ์ฆ(Authentication) | ์ฌ์ฉ์๊ฐ ๋๊ตฌ์ธ์ง ํ์ธ |
| ์ธ๊ฐ(Authorization) | ํด๋น ์ฌ์ฉ์๊ฐ ์ ๊ทผ ๊ถํ์ด ์๋์ง ํ์ธ |
3-2. ์ ํ ๋ฐ์ดํฐ ๋น๊ต
ํญ๋ชฉ๊ฐ์ ์ ๊ฐ์ ํ
| JwtFilter ์ฑ ์ | ์ธ์ฆ + ์ธ๊ฐ + ์ฌ์ฉ์ ์ ๋ณด ์ธํ + ์๋ฌ ์๋ต | ์์ฒญ ํ๋ฆ ์ ์ด + ์์ธ ์๋ต |
| JWT ์ฒ๋ฆฌ ๋ก์ง | JwtFilter ๋ด๋ถ | JwtAuthHelper๋ก ๋ถ๋ฆฌ |
| ๊ฐ๋ ์ฑ | ๋ฎ์ | ๊ฐ์ |
| ์ ์ง๋ณด์์ฑ | ๋ณ๊ฒฝ ์ง์ ์ด ๋ง์ | ์ญํ ๋ถ๋ฆฌ๋ก ๊ฐ์ |