Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Security Chain antMatchers ๊ด€๋ จ Exception Handling

Table of contents

  1. Error Response ๊ตฌ์„ฑ
  2. AccessDeniedHandler ๊ตฌํ˜„ํ•˜๊ธฐ
  3. AuthenticationEntryPoint ๊ตฌํ˜„ํ•˜๊ธฐ
  4. ํ™•์ธ


Security Chain ์„ค์ •์—์„œ,

ํŠน์ • Role๋งŒ Url ์š”์ฒญ์„ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •ํ• ๋•Œ (.hasRole() ๋˜์–ด์žˆ๋Š”) ํ˜น์€ .authenticated() ๋˜์–ด์žˆ๋Š” url์— AUTHORIZATION ๋‚ด์šฉ์ด ์•„์˜ˆ ์—†๋Š” ๊ฒฝ์šฐ

Chain์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” AccessDeniedHandler ์™€ AuthenticationEntryPoint ๋ฅผ ์ƒ์†๋ฐ›์•„ ๊ตฌํ˜„ํ•ด์•ผํ•œ๋‹ค.

์˜ˆ์‹œ๋กœ ์•„๋ž˜์™€ ๊ฐ™์ด ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.



Error Response ๊ตฌ์„ฑ


@RestControllerAdvice
@Slf4j
public class ExceptionManager {

    public static void setErrorResponse(HttpServletResponse response, ErrorCode errorCode) throws IOException {

        // ์—๋Ÿฌ ์‘๋‹ต์ฝ”๋“œ ์„ค์ •
        response.setStatus(errorCode.getHttpStatus().value());
        // ์‘๋‹ต body type JSON ํƒ€์ž…์œผ๋กœ ์„ค์ •
        response.setContentType("application/json;charset=UTF-8");

        Response<ErrorDto> error = Response.error(new ErrorDto(errorCode.toString(), errorCode.getMessage()));

        //์˜ˆ์™ธ ๋ฐœ์ƒ ์‹œ Error ๋‚ด์šฉ์„ JSONํ™” ํ•œ ํ›„ ์‘๋‹ต body์— ๋‹ด์•„์„œ ๋ณด๋‚ธ๋‹ค.
        Gson gson = new Gson();
        String responseBody = gson.toJson(error);

        response.getWriter().write(responseBody);
    }

}

@AllArgsConstructor
@Getter
public enum ErrorCode {

    TOKEN_NOT_FOUND(HttpStatus.UNAUTHORIZED, "ํ† ํฐ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."),
    FORBIDDEN_REQUEST(HttpStatus.FORBIDDEN, "ADMIN ํšŒ์›๋งŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.");
    
    private HttpStatus httpStatus;
    private String message;
}


๋จผ์ € ์œ„์™€ ๊ฐ™์€ ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค. ์—ฌ๋Ÿฌ๊ณณ์—์„œ ์“ฐ์ผ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, static ๋ฉ”์„œ๋“œ๋กœ ๋งŒ๋“ค์—ˆ๋‹ค.

HttpServletResponse ์— status ์™€ contentType ๋ฅผ ์„ค์ •ํ•˜๊ณ 

.getWriter.write() ๋ฉ”์„œ๋“œ๋กœ ์‘๋‹ตํ•  body๋ฅผ JSONํ™” ํ•ด์„œ ์‘๋‹ตํ•  ๋‚ด์šฉ์„ ์„ค์ •ํ•˜๋ฉด ๋œ๋‹ค.




AccessDeniedHandler ๊ตฌํ˜„ํ•˜๊ธฐ


import likelion.sns.Exception.ErrorCode;
import likelion.sns.Exception.ExceptionManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
@Slf4j
public class CustomAccessDeniedHandler implements AccessDeniedHandler {

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException {

        log.info("{}", accessDeniedException.getMessage());

        ErrorCode errorCode = ErrorCode.FORBIDDEN_REQUEST;

        ExceptionManager.setErrorResponse(response, errorCode);
    }
}


handle ์„ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•œ ํ›„, ์—๋Ÿฌ ๋ฐœ์ƒ์‹œ ์‘๋‹ตํ•  ์ฝ”๋“œ๋ฅผ ์„ค์ •ํ•˜๋ฉด ๋œ๋‹ค.

๊ทธ๋Ÿฌ๋ฉด .hasRole ๊ด€๋ จ ์˜ˆ์™ธ๋ฅผ ํ•ธ๋“ค๋งํ•  ์ˆ˜ ์žˆ๋‹ค.




AuthenticationEntryPoint ๊ตฌํ˜„ํ•˜๊ธฐ


import likelion.sns.Exception.ErrorCode;
import likelion.sns.Exception.ExceptionManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
@Slf4j
public class CustomAuthenticationEntryPointHandler implements AuthenticationEntryPoint {

    /**
     *  ํ† ํฐ ์—†์ด Security Chain ์—์„œ autenticated๋œ url ์ ‘๊ทผ ์‹œ, ์—๋Ÿฌ ํ•ธ๋“ค๋ง
     */
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
        final String authorization = request.getHeader(HttpHeaders.AUTHORIZATION);

        if (authorization == null) {
            log.error("ํ† ํฐ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.");
            ErrorCode errorCode = ErrorCode.TOKEN_NOT_FOUND;

            ExceptionManager.setErrorResponse(response, errorCode);
        }
    }
}


commence ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•˜๋ฉด ๋˜๊ณ , authorization์ด null ์ธ ์กฐ๊ฑด๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ, ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋ฉด ๋œ๋‹ค.




ํ™•์ธ

image-20221228215114914

ํ† ํฐ ์—†์ด ์š”์ฒญํ•  ๊ฒฝ์šฐ


image-20221228214807777

๊ถŒํ•œ ์—†๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์š”์ฒญํ•  ๊ฒฝ์šฐ