Search
Duplicate
๐Ÿ–ผ๏ธ

Request Scope ๋กœ ๋นˆ์˜ ์ƒ์•  ์ฃผ๊ธฐ ๊ด€๋ฆฌ

์ƒ์„ฑ์ผ
2022/06/08
ํƒœ๊ทธ
Spring

๋ฐฐ๊ฒฝ

๋ฏธ์…˜ ์ง„ํ–‰ ์ค‘, ์š”์ฒญํ•œ ์‚ฌ์šฉ์ž์— ๋Œ€ํ•œ ์ธ์ฆ์„ ์œ„ํ•ด token ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ jwt token ์„ ํŒŒ์‹ฑํ•˜๊ณ  ์œ ํšจ์„ฑ ๊ฒ€์ฆ์„ ํ•˜๋ ค๊ณ  ํ•˜๋‹ˆ, Interceptor ์—์„œ๋„ ํ•˜๊ณ  ArgumentResolver ์—์„œ๋„ ํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๋ฌธ์ œ์ 

Interceptor - ArgumentResolver ๋กœ ์ „๋‹ฌ๋˜๋Š” ์ธ์ž๋Š” Request(ServletRequest, WebRequest) ์ด๊ณ  ํ•ด๋‹น ๊ฐ์ฒด์—์„œ ๊บผ๋‚ผ ์ˆ˜ ์žˆ๋Š” ์ •๋ณด๋Š” getHeader() ๋กœ ๊บผ๋‚ผ ์ˆ˜ ์žˆ๋Š” ์ŠคํŠธ๋ง์ž…๋‹ˆ๋‹ค. ์ด์— ๋”ฐ๋ผ Interceptor ์—์„œ ํŒŒ์‹ฑ๊ณผ ์œ ํšจ์„ฑ ๊ฒ€์ฆ์„ ํ•˜๋Š”๋ฐ, ArgumentResolver ์—์„œ ์š”์ฒญ๋œ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ณ€ํ™˜ํ•˜๊ธฐ ์œ„ํ•ด ํŒŒ์‹ฑ์„ ๋˜ ํ•˜๊ฒŒ ๋˜๋Š” ์ค‘๋ณต ๋กœ์ง์ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๋‹ค๊ณ  ArgumentResolver ์—์„œ๋งŒ ํŒŒ์‹ฑ, ์œ ํšจ์„ฑ ๊ฒ€์ฆ, ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ณ€ํ™˜์„ ๋ชจ๋‘ ๋งก๊ธฐ๊ธฐ์—๋Š” ์ฑ…์ž„์ง€๋Š” ๋กœ์ง์ด ๋งŽ์•„์ ธ, ์ด ์ฑ…์ž„๋“ค์„ ๋ถ„๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์ƒ๊ฐํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

Interceptor

Handlerย ์ฒ˜๋ฆฌย ์ „๊ณผย ํ›„์—ย ์š”์ฒญ์—ย ๋Œ€ํ•œย ๊ณตํ†ต์ ์ธ ๋กœ์ง์„ย ์‹คํ–‰ํ• ย ์ˆ˜ย ์žˆ๋Š”ย AOPย ์„ฑ๊ฒฉ์„ย ์ง€๋‹™๋‹ˆ๋‹ค.

Argument Resolver

์ปจํŠธ๋กค๋Ÿฌ์˜ย ๋ฉ”์†Œ๋“œ์˜ย ์ธ์ž๋กœย ์‚ฌ์šฉ์ž๊ฐ€ย ์ž„์˜์˜ย ๊ฐ’์„ย ์ „๋‹ฌํ•˜๋Š”ย ๋ฐฉ๋ฒ•์„ย ์ œ๊ณตํ•˜๊ณ ์žย ํ• ย ๋•Œย ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
๋”ฐ๋ผ์„œ ํŒŒ์‹ฑ๊ณผ ์œ ํšจ์„ฑ ๊ฒ€์ฆ์€ Interceptor ์—์„œ ํ•˜๊ณ , ๊ฒ€์ฆ์„ ํ†ต๊ณผํ•˜๊ณ  ๋ฐ›์€ payload ๋Š” ArgumentResolver ๋กœ ์ „๋‹ฌํ•œ ๋’ค ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๋กœ์ง์„ ๊ตฌ์ƒํ•˜์˜€์Šต๋‹ˆ๋‹ค.

Request ์˜ Attribute

์ฒ˜์Œ์—๋Š”ย ๊ฐย ํŒŒ๋ผ๋ฏธํ„ฐ๋กœย ๋ฐ›๋Š”ย Requestย ์—์„œย attributeย ๋ฅผย ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ƒ๊ฐํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค.ย Interceptorย ์—์„œ๋Š”ย ์œ ํ˜ธ์„ฑ ๊ฒ€์ฆ์„ ๋งˆ์นœย payloadย ๋ฅผย attributeย ์—ย setย ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ ย Argumentย Resolverย ์—์„œ๋Š”ย attributeย ์—์„œย getย ํ•œ ๋’ค ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๋กœ์ง์ž…๋‹ˆ๋‹ค.ย ๊ฐ™์€ย Requestย Contextย ์•ˆ์—ย ์žˆ์–ด์„œย ์ „๋‹ฌ์ดย ๊ฐ€๋Šฅํ–ˆ๊ณ ,ย ํ•˜๋‚˜์˜ย ์š”์ฒญ์ดย ๋๋‚˜๋ฉดย ์‚ฌ๋ผ์ ธ ์ดํ›„์˜ ์š”์ฒญ์— ์ค‘๋ณต์˜ ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

Scope

์œ„์™€ ๊ฐ™์ด Request ์˜ attribute ๋ฅผ ์ด์šฉํ•˜๋Š” ๊ฒƒ๋„ ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜์ด์ง€๋งŒ, ์ธ์ฆ๊ณผ ๊ด€๋ จํ•ด์„œ ์ง์ ‘ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด๊ฐ€ ์žˆ์œผ๋ฉด ์ข‹๊ฒ ๋‹ค๋ผ๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ์œ„์˜ ๋ฐฉ๋ฒ•์€ servlet ์˜ attribute ๊ธฐ๋Šฅ๊ณผ ๊ด€๋ จํ•˜์—ฌ Map ๊ตฌ์กฐ๋กœ ๋ฐ–์— ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ธฐ์— ์ดํ›„ ํ™•์žฅ์˜ ์ธก๋ฉด์—์„œ ๋‹จ์ ์ด ์žˆ์„ ๊ฒƒ์ด๋ผ ํŒ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด์— ๋”ฐ๋ผ request ์™€ ๊ฐ™์€ ๋ผ์ดํ”„ ์‚ฌ์ดํด์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค๊ธฐ๋กœ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
@Componen @Scope(value = SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS) public class RequestTokenContext { private String customerId; public String getCustomerId() { return customerId; } public void setCustomerId(String customerId) { this.customerId = customerId; } }
Java
๋ณต์‚ฌ
1.ย ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•˜๋ฉฐ ๋ผ์ดํ”„์‚ฌ์ดํด ์ฃผ๊ธฐ๋ฅผ ์Šคํ”„๋ง์— ๋งก๊ธฐ๋ฉด์„œ, value = SCOPE_REQUEST ์˜ต์…˜์œผ๋กœ ํ•ด๋‹น ์ฃผ๊ธฐ๋ฅผ request ๋กœ ์ •ํ•˜์˜€์Šต๋‹ˆ๋‹ค.
๋‘ ๋ฒˆ์งธ ์˜ต์…˜์ธ Proxy mode ๋Š” ์„œ๋ฒ„๊ฐ€ ๋œฐ ๋•Œ ๊ฐ€์งœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์ฃผ๋Š” ์˜ต์…˜์ธ๋ฐ ์ดํ›„์— ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
@Component public class AuthenticationInterceptor implements HandlerInterceptor { private final RequestTokenContext requestTokenContext; public AuthenticationInterceptor(RequestTokenContext requestTokenContext) { this.requestTokenContext = requestTokenContext; } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { final String token = getTokenFromHeader(); validateToken(token); final String payload = getPayload(token); validatePayload(payload); requestTokenContext.setCustomerId(payload); return true; } }
Java
๋ณต์‚ฌ
RequestTokenContextย ๊ฐ์ฒด์—ย payloadย ๋ฅผย set ํ•ฉ๋‹ˆ๋‹ค. RequestTokenContext ์€ย ํ•˜๋‚˜์˜ย ์š”์ฒญ์ดย ๋๋‚ ย ๋•Œย ๊นŒ์ง€ย ๋นˆ์œผ๋กœย ๋“ฑ๋ก๋˜์–ดย ์‚ฌ์šฉ์ดย ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
@Component public class AuthenticationPrincipalArgumentResolver implements HandlerMethodArgumentResolver { private final RequestTokenContext requestTokenContext; // ์ƒ์„ฑ์ž ์ƒ๋žต @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(AuthenticationPrincipal.class); } @Override public Long resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) { return Long.parseLong(requestTokenContext.getCustomerId()); } }
Java
๋ณต์‚ฌ
Interceptor ์—์„œ ๋“ฑ๋กํ•œย payloadย ๋ฅผย ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. ArgumentResolver ์—์„œ๋Š” ํ•ด๋‹น payload ๋ฅผ ๊ฒ€์ฆํ•˜์ง€ ์•Š๊ณ  ๋ฐ”๋กœ parameter ๋กœ ๋„˜๊ธธ ์ˆ˜ ์žˆ๋„๋ก ๋กœ์ง์„ ๊ตฌ์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.
์œ„์˜ ๋ฐฉ์‹์œผ๋กœ ๋‘ ๊ฐ€์ง€ ์žฅ์ ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
1.
์ค‘๋ณต๋œ ๋กœ์ง์„ ํ”ผํ•  ์ˆ˜ ์žˆ๋‹ค.
โ€ข
getHeader() ๋กœ Interceptor ์™€ ArgumentResolver ์—์„œ ํŒŒ์‹ฑ๊ณผ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๋“ฑ์˜ ๋กœ์ง์ด ์ค‘๋ณต๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
2.
์ดํ›„ ๊ฐ™์€ ์š”์ฒญ ์ฃผ๊ธฐ์˜ Controller, Service ๋“ฑ์—์„œ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
โ€ข
๋นˆ์œผ๋กœ ๋“ฑ๋กํ•˜์˜€๊ธฐ๋•Œ๋ฌธ์— ๋ผ์ดํ”„์‚ฌ์ดํด์˜ ์‚ด์•„์žˆ๋Š” ๋™์•ˆ ์–ด๋–ค ๊ณ„์ธต์—์„œ๋“ , ์ฃผ์ž…์„ ๋ฐ›๊ธฐ๋งŒ ํ•˜๋ฉด ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.