Dev/Spring Boot

์Šคํ”„๋ง์˜ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ2(Filter, Interceptor)

OK-๊ฐ€์ž 2022. 3. 2. 17:41

Interceptor

๐Ÿ˜Ž๐Ÿค”๐Ÿฆœ
Interceptor ๋ž€ Filter ์™€ ๋งค์šฐ ์œ ์‚ฌํ•œ ํ˜•ํƒœ๋กœ ์กด์žฌ ํ•˜์ง€๋งŒ, ์ฐจ์ด์ ์€ Spring Context์— ๋“ฑ๋ก ๋œ๋‹ค.
AOP์™€ ์œ ์‚ฌํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณต ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ฃผ๋กœ ์ธ์ฆ๋‹จ๊ณ„๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ฑฐ๋‚˜, Logging๋ฅผ ํ•˜๋Š” ๋ฐ์— ์‚ฌ์šฉํ•œ๋‹ค.
์ด๋ฅผ ์„ /ํ›„ ์ฒ˜๋ฆฌ ํ•จ์œผ๋กœ์จ, Service business logic ๊ณผ ๋ถ„๋ฆฌ ์‹œํ‚จ๋‹ค.

๋ฐฑ๋ฌธ์ด๋ถˆ์—ฌ์ผํƒ€

์ธ์ฆ๊ด€๋ฆฌํ•˜๋Š” ์ธํ„ฐ์…‰ํ„ฐ ๋งŒ๋“ค์–ด๋ณด์ž

session์ด๋‚˜ ์ฟ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ•˜์ง€๋งŒ... ์ธํ„ฐ์…‰ํ„ฐ ์‹ค์Šต์ด๊ธฐ ๋•Œ๋ฌธ์— ํ•„๋“œ๊ฐ’๋ฐ›์•„์„œ ํ™•์ธ

@Auth
@RestController
@RequestMapping("/api/private")
public class PrivateController {

    @GetMapping("/hello")
    public String hello() {
        return "private hello";
    }
}
@RestController
@RequestMapping("/api/public")
public class PublicController {

    @GetMapping("/hello")
    public String hello() {
        return "public hello";
    }
}

Private์ปจํŠธ๋กค๋Ÿฌ์™€ Public ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๋งŒ๋“ค๊ณ  Private์—๋Š” @Auth๋ฅผ ๋ถ‡์—ฌ์ค€๋‹ค.(์ธ์ฆ์„ ํ†ต๊ณผํ•ด์•ผ ์ปจํŠธ๋กค๋Ÿฌ์— ์ ‘๊ทผ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ• ๊บผ๋‹ค.)

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Auth {
}

๐Ÿฆœ @Auth ์–ด๋…ธํ…Œ์ด์…˜ ๋งŒ๋“ค์–ด์ฃผ๊ณ 

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

        String url = request.getRequestURI();
        log.info("request url : {}", url);

        return false;
    }

    private boolean checkAnnotation(Object handler, Class clazz) {
        // resource javascript, html
        if (handler instanceof ResourceHttpRequestHandler) {
            return true;
        }

        //anntation check
        HandlerMethod handlerMethod = (HandlerMethod) handler;

        if (null != handlerMethod.getMethodAnnotation(clazz) || null != handlerMethod.getBeanType().getAnnotation(clazz)) {
            // Auth anntation ์ด ์žˆ์„๋•Œ๋Š” true
            return true;
        }
        return false;
    }
}

๐Ÿฆœ AuthInterceptor ํด๋ž˜์Šค์— ์กฐ๊ฑด๋“ค์„ ๋‹ฌ์•„์ค€๋‹ค.

@Configuration
@RequiredArgsConstructor //fianl๋กœ ์„ ์–ธํ•œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ์—์„œ ์ฃผ์ž…๋ฐ›์„์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.
public class MvcConfig implements WebMvcConfigurer {

    private final AuthInterceptor authInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authInterceptor);
    }
}

๐Ÿฆœ ์—ฌ๊ธฐ์„œ ์ฃผ์˜ํ• ์  ์—ฌ๊ธฐ์„œ ์ƒ์„ฑ์ž ์ฃผ์ž…ํ• ๋•Œ ์ด๋•Œ๊นŒ์ง€ ๋‚œ @Autowierd๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค.

์ด๋ ‡๊ฒŒ ๋ง์ด๋‹ค.
ํ•˜์ง€๋งŒ ์ˆœํ™˜์ฐธ์กฐ๊ฐ€ ์ผ์–ด๋‚ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— @RequiredArgsConstructor ๋ฅผ ์“ด๋‹ค.
@RequiredArgsConstructor๋Š” final๋กœ ์„ ์–ธ๋œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์„œ ์ฃผ์ž…๋ฐ›์„์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜์ด๋‹ค.!!!!! ๊ฟ€ํŒ์ด๋‹ค.!!!
๐Ÿฆœ ๊ทธ๋Ÿผ ํ˜ธ์ถœํ•œ๋ฒˆํ•ด๋ณด์ž.

๐Ÿฆœ privateController๋กœ ํ˜ธ์ถœํ•˜๋ฉด ์ปจํŠธ๋กค๋Ÿฌ๊นŒ์ง€ ๋ชป์˜จ๋‹ค. AuthInterceptor์—์„œ ๋ง‰์•„๋ฒ„๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๐Ÿฆœ ์ž์ด์ œ ๊ทธ๋Ÿผ ๊ถŒํ•œ์ฒดํฌํ•˜๋Š” ์˜ˆ์‹œ๋ฅผ ์งœ๋ณด์ž. ๐Ÿค”์–ด๋–ป๊ฒŒ?ํ• ๊นŒ?๐Ÿค”

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        URI uri = UriComponentsBuilder.fromUriString(request.getRequestURI())
                .query(request.getQueryString())
                .build()
                .toUri();
        // ์›๋ž˜๋Š” Sessionํ™•์ธํ•˜๊ฑฐ๋‚˜ ์ฟ ํ‚คํ™•์ธํ•œ๋‹ค!!!!!

        String url = request.getRequestURI();
        log.info("request url : {}", url);

        boolean hasAnnotation = checkAnnotation(handler, Auth.class);
        log.info("has annotation : {}", hasAnnotation); // Auth์–ด๋…ธํ…Œ์ด์…˜์ด ๋‹ฌ๋ ค์žˆ๋‚˜??? ํ™•์ธํ•˜๊ธฐ.

        // ๋‚˜์˜ ์„œ๋ฒ„๋Š” ๋ชจ๋‘  public ์œผ๋กœ ๋™์ž‘์„ ํ•˜๋Š”๋ฐ
        // ๋‹จ! Auth ๊ถŒํ•œ์„ ๊ฐ€์ง„ ์š”์ฒญ์— ๋Œ€ํ•ด์„œ๋Š” ์„ธ์…˜,์ฟ ํ‚ค ๋“ฑ๋“ฑ์„ ํ™•์ธํ•œ๋‹ค!!!!!

        if(hasAnnotation){
            //๊ถŒํ•œ์ฒดํฌ
            String query = uri.getQuery();
            if(query.equals("name=steve")){
                return true; // ์ด๋ฆ„์ด ์Šคํ‹ฐ๋ธŒ์ผ๋•Œ๋งŒ ํ†ต๊ณผํ•œ๋‹ค.
            }
        }
        return false;
    }

๐Ÿค”๐Ÿค” ๊ทธ๋Ÿผ ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ์ปจํŠธ๋กค๋Ÿฌ์˜ ๋ฉ”์„œ๋“œ๋งŒ ์ธํ„ฐ์…‰ํ„ฐ๊ฐ€ ๋™์ž‘ํ•˜๊ฒŒ ๋ชปํ•˜๋‚˜?

@Configuration
@RequiredArgsConstructor //fianl๋กœ ์„ ์–ธํ•œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ์—์„œ ์ฃผ์ž…๋ฐ›์„์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.
public class MvcConfig implements WebMvcConfigurer {

    private final AuthInterceptor authInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authInterceptor).addPathPatterns("/api/private/*");//๋‚ด๊ฐ€ ๊ฒ€์‚ฌํ•˜๊ณ ์‹ถ์€ ์ฃผ์†Œ์„ค์ •
        //excludePathPatterns()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŠน์ • ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๋บ„์ˆ˜ ์žˆ๋‹ค.
    }
}

๐Ÿฆœ MvcConfig์— ์ธํ„ฐ์…‰ํ„ฐ ํŒจํ„ด์„ ์ž…๋ ฅํ•˜์—ฌ ํŠน์ •์ปจ๋“œ๋กค๋Ÿฌ๋ฅผ ๋นผ๊ฑฐ๋‚˜ ์„ค์ • ํ•  ์ˆ˜ ์žˆ๋‹ค.!!

๐Ÿฆœ ๊น”๋”ํ•˜๊ฒŒ ์˜ˆ์™ธ์ฒ˜๋ฆฌ๊นŒ์ง€ ํ•ด์ฃผ์ž

        if(hasAnnotation){
            //๊ถŒํ•œ์ฒดํฌ
            String query = uri.getQuery();
            if(query.equals("name=steve")){
                return true; // ์ด๋ฆ„์ด ์Šคํ‹ฐ๋ธŒ์ผ๋•Œ๋งŒ ํ†ต๊ณผํ•œ๋‹ค.
            }

            //๊ถŒํ•œ์ด ์—†์œผ๋ฉด?? AuthException๋กœ ๋˜์ ธ์ค€๋‹ค.
            throw new AuthException();
        }

AuthInterceptor์˜ ๊ถŒํ•œ์ฒดํฌ๊ฐ€ ์‹คํŒจํ•˜๋ฉด
AuthExeption์œผ๋กœ ๋˜์ ธ์ฃผ๊ณ 

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(AuthException.class)
    public ResponseEntity authException(){
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
    }

}

๐Ÿฆœ ๊ทธ๊ฑธ GlobalExceptionHandler๊ฐ€ ์ฒ˜๋ฆฌํ•ด์ค€๋‹ค.

)

steve๊ฐ€ ์•„๋‹ˆ๋ฉด ํ˜ธ์ถœ์ด ์•ˆ๋œ๋‹ค!! ์„ฑ๊ณต!!!