Spring/Spring Security

[Spring Security] 핸들러(예외) 처리

제우제우 2024. 9. 2. 23:15

[400] AuthenticationFailureHandler (인증 실패 핸들러: 로그인 실패 핸드러) 

@Slf4j
@RequiredArgsConstructor
public class LoginFailHandler implements AuthenticationFailureHandler {
    private final ObjectMapper objectMapper;
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        log.info("[인증 오류] 아이디 혹은 비밀번호가 올바르지 않습니다.");

        ErrorResponse errorResponse = ErrorResponse.builder()
                .code("400")
                .message("아이디 혹은 비밀번호가 올바르지 않습니다.")
                .build();

        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding(StandardCharsets.UTF_8.displayName());
        response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
        objectMapper.writeValue(response.getWriter(), errorResponse);
    }
}

 

사용자의 잘못된 요청(아이디 혹은 비밀번호가 틀린 경우): 400 BAD_REQUEST 

ErrorResponse(커스텀 객체) 반환 

 

[401] AuthenticationEntryPoint (권한이 필요한 경우: 로그인을 안한 상태)

@Slf4j
@RequiredArgsConstructor
public class Http401Handler implements AuthenticationEntryPoint {
    private final ObjectMapper objectMapper;
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        log.info("[인증 오류] 로그인이 필요합니다.");

        ErrorResponse errorResponse = ErrorResponse.builder()
                              .code("401")
                              .message("로그인이 필요합니다")
                              .build();

       response.setContentType(MediaType.APPLICATION_JSON_VALUE);
       response.setCharacterEncoding(StandardCharsets.UTF_8.displayName());
       response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
       objectMapper.writeValue(response.getWriter(), errorResponse);
    }
}

403 UNAUTHORIZED

 

[403] AccessDeniedHandler(접근 불가 처리 핸들러)

@Slf4j
@RequiredArgsConstructor
public class Http403Handler implements AccessDeniedHandler {
    private final ObjectMapper objectMapper;
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        log.info("[인증 오류] 권한이 부족합니다.");

        ErrorResponse errorResponse = ErrorResponse.builder()
                       .code("403")
                       .message("권한이 부족합니다.")
                       .build();

        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding(StandardCharsets.UTF_8.displayName());
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        objectMapper.writeValue(response.getWriter(), errorResponse);
    }
}

로그인은 했지만 접근 권한이 없는 경우 

 

EX)

관리자 권한만 접근 가능한 페이지에 접속하려고 하는 경우 hasRole("ADMIN") 

403 FORBIDDEN

 

 

핸들러 SecurityFilterChain 설정 

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{
    return http
            .authorizeHttpRequests(
                    authorize -> authorize
                    .requestMatchers("/auth/login").permitAll()
                    .requestMatchers("/auth/signup").permitAll()
                    .requestMatchers("/user").hasRole("USER")
                    .requestMatchers("/admin").hasRole("ADMIN")
                    .anyRequest().authenticated())
            .csrf(AbstractHttpConfigurer::disable) 
            .formLogin(login -> login
                    .loginPage("/auth/login")
                    .loginProcessingUrl("/auth/login")
                    .usernameParameter("username")
                    .passwordParameter("password")
                    .defaultSuccessUrl("/")
                    .failureHandler(new LoginFailHandler(objectMapper))
            )
            .rememberMe(rm -> rm
                        .rememberMeParameter("remember")
                        .alwaysRemember(false) 
                        .tokenValiditySeconds(2592000))
            .exceptionHandling(e -> {
                e.accessDeniedHandler(new Http403Handler(objectMapper));
                e.authenticationEntryPoint(new Http401Handler(objectMapper));
            })
            .build();
}

 

 

AuthenticationEntryPoint,  AccessDeniedHandler

.exceptionHandling(e -> {
                e.accessDeniedHandler(new Http403Handler(objectMapper));
                e.authenticationEntryPoint(new Http401Handler(objectMapper));
            })

 

 

권한 부족, 권한이 없는 경우 처리 

 

AuthenticationFailureHandler

.formLogin(login -> login
        .loginPage("/auth/login")
        .loginProcessingUrl("/auth/login")
        .usernameParameter("username")
        .passwordParameter("password")
        .defaultSuccessUrl("/")
        .failureHandler(new LoginFailHandler(objectMapper))
)

 

로그인 실패 처리