쌓고 쌓다

Spring Security 인증/인가 예외 JSON 처리 본문

프로그래밍/spring

Spring Security 인증/인가 예외 JSON 처리

승민아 2024. 1. 24. 13:45

시큐리티 설정을  통해 인증, 인가 설정을 할 수 있다.

 

 

이제 이 인증, 인가에 실패했을 경우에 JSON 예외 응답을 보내보자.

 

SecurityConfig.java

http.exceptionHandling(e -> e
	.authenticationEntryPoint(new JwtAuthenticationEntryPoint())
	.accessDeniedHandler(new JwtAccessDenyHandler()));

exceptionHandling을 통해 예외를 처리할 로직은 시큐리티에 등록할 수 있다.

 

인증 예외는 AuthenticationEntryPoint 인터페이스를 구현하여 등록할 수 있고

인가 예외는 AccessDeniedHandler 인터페이스를 구현하여 등록할 수 있다.

 

먼저 Enum 타입으로 작성해둔 예외 종류와 메시지를 보자.

 

ErrorCode

import lombok.Getter;
import org.springframework.http.HttpStatus;

@Getter
public enum ErrorCode {

    UNAUTHORIZED_CLIENT(HttpStatus.BAD_REQUEST, "접근 토큰이 없습니다."),
    FORBIDDEN_CLIENT(HttpStatus.FORBIDDEN, "접근 권한이 없습니다."),
    EXPIRED_TOKEN(HttpStatus.UNAUTHORIZED, "만료된 토큰입니다."),
    JWT_DECODE_FAIL(HttpStatus.UNAUTHORIZED, "올바른 토큰이 필요합니다."),
    JWT_SIGNATURE_FAIL(HttpStatus.UNAUTHORIZED, "올바른 토큰이 필요합니다.");

    private HttpStatus httpStatus;
    private String message;


    ErrorCode(HttpStatus httpStatus, String message) {
        this.httpStatus = httpStatus;
        this.message = message;
    }
}

 

ErrorResponse

import com.example.spotserver.exception.ErrorCode;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
public class ErrorResponse {

    private String errorCode;
    private String message;

    public ErrorResponse(ErrorCode errorCode) {
        this.errorCode = errorCode.name();
        this.message = errorCode.getMessage();
    }
}

ErrorCode를 통해 에러 응답을 설정하여 응답으로 보낼 클래스이다.

 

JwtAccessDenyHandler (AccessDeniedHandler 구현체)

public class JwtAccessDenyHandler implements AccessDeniedHandler {

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        ErrorResponse errorResponse = new ErrorResponse(ErrorCode.FORBIDDEN_CLIENT);
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonErrorResponse = objectMapper.writeValueAsString(errorResponse);

        response.setStatus(HttpStatus.FORBIDDEN.value());
        response.setCharacterEncoding("utf-8");
        response.setContentType(MediaType.APPLICATION_JSON_VALUE); // application/json
        response.getWriter().write(jsonErrorResponse);
    }
    
}
  • handle() : 예외 발생시 처리할 로직이다.
  • ObjectMapper : 객체를 JSON 형태로 바꿔 응답을 보내기위해 writeValueAsString을 사용한다.
  • setStatus : HTTP 상태 코드 설정
  • setCharacterEncoding : 한글이 깨져서 응답이 나갈 수 있다. 문자열 인코딩을 설정해주자.

 

JwtAuthenticationEntryPoint (AuthenticationEntryPoint 구현체)

import com.example.spotserver.domain.ErrorResponse;
import com.example.spotserver.exception.ErrorCode;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.web.bind.annotation.ExceptionHandler;

import java.io.IOException;

public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        ErrorResponse errorResponse = new ErrorResponse(ErrorCode.UNAUTHORIZED_CLIENT);
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonErrorResponse = objectMapper.writeValueAsString(errorResponse);

        response.setStatus(HttpStatus.BAD_REQUEST.value());
        response.setCharacterEncoding("utf-8");
        response.setContentType(MediaType.APPLICATION_JSON_VALUE); // application/json
        response.getWriter().write(jsonErrorResponse);
    }

}

 

 

이제 인증/인가 예외 발생시 다음과 같이 JSON 응답을 줄 수 있다.

인가 예외

 

인증 예외

 

JWT 토큰과 관련된 예외는 필터를 걸고 Authorization 헤더가 존재하면 검증하는 로직에

다음과 같이 예외를 잡고 처리할 수 있다.

 

JWT 토큰 예외

Comments