Spring Interceptor

์ด์ข…์ฐฌยท2023๋…„ 2์›” 15์ผ
0

๐Ÿ“– Interceptor?

Spring์—์„œ ์ œ๊ณตํ•˜๋Š” AOP(Aspect Oriented Programming) ์˜ ํ•œ ์ข…๋ฅ˜๋กœ, ์ปจํŠธ๋กค๋Ÿฌ ์‹คํ–‰ ์ „/ํ›„์— ํŠน์ • ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. ์ฃผ๋กœ ์ธ์ฆ ๋‹จ๊ณ„๋ฅผ ์ฒ˜๋ฆฌ ํ•˜๊ฑฐ๋‚˜, ๋กœ๊น…ํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. -> ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ๋ถ„๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

HandlerInterceptor ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ , preHandle(),postHandle(), afterCompletion() ๋ฉ”์„œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•˜์—ฌ ์ปจํŠธ๋กค๋Ÿฌ ์‹คํ–‰ ์ „/ํ›„์— ํŠน์ • ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Interceptor๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๋‘๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  1. WebMvcConfigurer๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ addInterceptors() ๋ฉ”์„œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋”ฉ ํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋•Œ์— ๋”ฐ๋ผ addPathPatterns() ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŠน์ • URL์—๋งŒ ์ ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

  2. @Interceptor๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Bean์œผ๋กœ ๋“ฑ๋กํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿค” ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์ด์œ ๋Š”?

์ธํ„ฐ์…‰ํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ชจ๋“  ์š”์ฒญ์—์„œ ๊ณตํ†ต์„ ์‚ฌ์šฉํ•˜๋Š” ๋กœ์ง์„ Interceptor์—์„œ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ค‘๋ณต ์ฝ”๋“œ๋ฅผ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ๋กœ๊น…, ์ธ์ฆ, ๊ถŒํ•œ ๊ฒ€์‚ฌ, ์บ์‹œ ์ฒ˜๋ฆฌ ๋“ฑ ๋งŽ์€ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿค” Filter vs Interceptor

์ด์ „์— ๊ณต๋ถ€ํ•œ Filter์™€ ๋งŽ์ด ์œ ์‚ฌํ•˜๋‹ค๊ณ  ๋Š๊ผˆ์Šต๋‹ˆ๋‹ค. Filter๊ฐ€ ๋จผ์ € ์‹คํ–‰๋˜๊ณ  Interceptor๊ฐ€ ์‹คํ–‰์ด ๋˜๋Š”๋ฐ ์–ด๋– ํ•œ ์ฐจ์ด์ ์ด ์žˆ๋Š”์ง€ ๊ถ๊ธˆํ•˜์—ฌ ์•Œ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค.

FilterInterceptor
์ ์šฉ ๋ฒ”์œ„์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์—์„œ ์ฒ˜๋ฆฌ๋˜๋Š” ๋ชจ๋“  ์š”์ฒญ์— ๋Œ€ํ•ด ์ ์šฉ ๊ฐ€๋Šฅ์Šคํ”„๋ง์˜ DispathcherServlet์ด ์ฒ˜๋ฆฌํ•˜๋Š” ์š”์ฒญ์— ๋Œ€ํ•ด์„œ๋งŒ ์ ์šฉ ๊ฐ€๋Šฅ
์ฒ˜๋ฆฌ ์‹œ์ ์š”์ฒญ ์ฒ˜๋ฆฌ ์ „ํ›„๋กœ ์ „์ฒ˜๋ฆฌ ํ›„ ํ›„์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ์š”์ฒญ ์ฒ˜๋ฆฌ ์ „์—๋งŒ ์ „์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ
์ ์šฉ ๋ฐฉ๋ฒ•web.xml์— ๋“ฑ๋กํ•˜๊ฑฐ๋‚˜ @WebFilter ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ๋“ฑ๋ก์ธํ„ฐ์…‰ํ„ฐ๋ฅผ ๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค๋ฅผ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•˜๊ณ , ์ธํ„ฐ์…‰ํ„ฐ๋ฅผ ๋“ฑ๋กํ•˜๋Š” InterceptorRegistry ํด๋ž˜์Šค์˜ addInterceptor() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋“ฑ๋ก
์ ์šฉ ์šฉ๋„์š”์ฒญ ๋ฐ ์‘๋‹ต์— ๋Œ€ํ•œ ์ „์—ญ์ ์ธ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐํŠน์ • ์ปจํŠธ๋กค๋Ÿฌ์˜ ์š”์ฒญ์— ๋Œ€ํ•ด ๊ณตํ†ต์ ์ธ ์ „์ฒ˜๋ฆฌ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ฑฐ๋‚˜, ํŠน์ • ์กฐ๊ฑด์— ๋”ฐ๋ผ ์š”์ฒญ์„ ๋ง‰์•„์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ

๐Ÿ‘จโ€๐Ÿ’ป ๊ตฌํ˜„

@Auth์„ ๊ฐ€์ง„ Request๊ฐ€ ์˜ค๋ฉด ์ฟผ๋ฆฌ๋ฅผ ๊ฒ€์‚ฌํ•˜๋Š” ๋กœ์ง์„ ๋งŒ๋“ค์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

MvcConfig

@Configuration
@RequiredArgsConstructor
public class MvcConfig implements WebMvcConfigurer {
    private final AuthInterceptor authInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //addPathPatterns์— ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ์ฃผ์†Œ๋งŒ ๋„ฃ์–ด๋„ ๋œ๋‹ค.
        registry.addInterceptor(authInterceptor).addPathPatterns("/api/private/*");
    }
}

์Šคํ”„๋ง MVC์—์„œ ์ธํ„ฐ์…‰ํ„ฐ๋ฅผ ์„ค์ •ํ•˜๊ธฐ ์œ„ํ•œ MvcConfig์ž…๋‹ˆ๋‹ค.

@Configuration ์–ด๋…ธํ…Œ์ด์…˜์€ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์—๊ฒŒ ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ Bean ๊ตฌ์„ฑ ํด๋ž˜์Šค๋กœ ์ธ์‹ํ•˜๋„๋ก ์ง€์ •ํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ํ•ด๋‹น ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ์Šคํ”„๋ง์€ ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ ๊ตฌ์„ฑ ํด๋ž˜์Šค๋กœ ์ธ์‹ํ•˜์—ฌ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰ ์‹œ์— Bean๋“ค์„ ์ƒ์„ฑํ•˜๊ณ  ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.
@RequireArgsConstructor๋Š” ์ƒ์„ฑ์ž๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜๋Š” Lombok ์–ด๋…ธํ…Œ์ด์…˜์ž…๋‹ˆ๋‹ค.

WebMvcConfigurer addInterceptors() ๋ฉ”์„œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•˜๋ฉด, ํ•ด๋‹น ๋ฉ”์„œ๋“œ์—์„œ ์ธํ„ฐ์…‰ํŠธ๋ฅผ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ถ€๊ฐ€์ ์œผ๋กœ addPathPatterns() ์‚ฌ์šฉํ•˜์—ฌ ํŠน์ • URL์—์„œ๋งŒ ์ž‘๋™ํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

AuthInterceptor

@Slf4j
@Component
public class AuthInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        URI uri = UriComponentsBuilder.fromUriString(request.getRequestURI())
                .query(request.getQueryString())
                .build()
                .toUri();

        boolean hasAnnotation = checkAnnotation(handler, Auth.class);
        log.info("has Annotation : {}", hasAnnotation);
        
        //Auth ๊ถŒํ•œ์„ ๊ฐ€์ง„ ์š”์ฒญ์— ๋Œ€ํ•ด์„œ๋งŒ ์„ธ์„ ,์ฟ ํ‚ค ๋“ฑ์„ ๊ฒ€์‚ฌ
        if (hasAnnotation) { //๊ถŒํ•œ ์ฒดํฌ
            String query = uri.getQuery();
            log.info("query : {}", query);
            return query.contains("name=Chan");
        }

        //return value -> false : filter -> dispatcher -> interceptor -> ์ง„์ž… ๋ถˆ๊ฐ€.
        return true;
    }

    private boolean checkAnnotation(Object handler, Class clazz) {
        //resource javascript, html ๋Š” ํ†ต๊ณผ ์‹œํ‚จ๋‹ค.
        if (handler instanceof ResourceHttpRequestHandler) {
            return true;
        }

//        annotation check
        HandlerMethod method = (HandlerMethod) handler;

        log.info("get annotation : {}", method.getMethodAnnotation(clazz));
        log.info("get bean type : {}", method.getBeanType().getAnnotation(clazz));

        if (method.getMethodAnnotation(clazz) != null ||
                method.getBeanType().getAnnotation(clazz) != null) {
            //Auth annotation ์ด ์žˆ์œผ๋ฉด true

            return true;
        }

        return false;
    }
}

checkAnnotation์—์„œ @Auth์˜ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜์—ฌ ๋ฆฌํ„ดํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ @Auth๊ฐ€ ์‚ฌ์šฉ๋œ Request๋ฉด ์ฟผ๋ฆฌ๋ฌธ์„ ๊ฒ€์‚ฌํ•˜์—ฌ name=Chan์ธ์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. false๋ฉด ์ธํ„ฐ์…‰ํ„ฐ์„ ์—์„œ ์ข…๋ฃŒ๊ฐ€ ๋˜๊ธฐ ๋•Œ๋ฌธ์— Response๊ฐ’์„ ํด๋ผ์ด์–ธํŠธ๋Š” ๋ฐ›์ง€ ๋ชปํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์‹คํ–‰๊ฒฐ๊ณผ (์ฟผ๋ฆฌ๋ฌธ ์ผ์น˜)

{
"name": "Chan",
"age": 111
}

์‹คํ–‰๊ฒฐ๊ณผ (์ฟผ๋ฆฌ๋ฌธ ๋ถˆ์ผ์น˜)

No Content

์‹คํ–‰๊ฒฐ๊ณผ (@Auth ๋ฏธ์‚ฌ์šฉ

{
"name": "ใ…ใ…ใ…",
"age": 111
}

โœ… ์š”์•ฝ

  • Spring์—์„œ ์ œ๊ณตํ•˜๋Š” AOP์˜ ํ•œ์ข…๋ฅ˜๋กœ ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์‹คํ–‰ ์ „/ํ›„์—์„œ ์ž‘์—…ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋ชจ๋“  ์š”์ฒญ์—์„œ ๊ณตํ†ต์ ์ธ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•  ๋•Œ ์ธํ„ฐ์…‰ํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹๋‹ค.
  • ์ธํ„ฐ์…‰ํŠธ๋Š” WebMvcConfigurer, @Interceptor๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋‚˜๋‰œ๋‹ค.
  • Filter์™€ ์œ ์‚ฌํ•˜์ง€๋งŒ ์ ์šฉ๋ฒ”์œ„์™€ ์—ญํ• ์ด ๋‹ค๋ฅด๋‹ค.
profile
์™œ? ๋ผ๋Š” ์งˆ๋ฌธ์ด ์‚ฌ๋ผ์งˆ ๋•Œ๊นŒ์ง€

0๊ฐœ์˜ ๋Œ“๊ธ€