diff --git a/src/main/java/com/postgraduate/domain/auth/presentation/contant/AuthResponseCode.java b/src/main/java/com/postgraduate/domain/auth/presentation/contant/AuthResponseCode.java index 6b9f8202..5c61276d 100644 --- a/src/main/java/com/postgraduate/domain/auth/presentation/contant/AuthResponseCode.java +++ b/src/main/java/com/postgraduate/domain/auth/presentation/contant/AuthResponseCode.java @@ -15,6 +15,7 @@ public enum AuthResponseCode { AUTH_DENIED("EX900"), AUTH_INVALID_KAKAO("EX901"), - AUTH_KAKAO_CODE("EX902"); + AUTH_KAKAO_CODE("EX902"), + AUTH_FAILED("EX903"); private final String code; } diff --git a/src/main/java/com/postgraduate/domain/auth/presentation/contant/AuthResponseMessage.java b/src/main/java/com/postgraduate/domain/auth/presentation/contant/AuthResponseMessage.java index 1f7efbcb..cda4bafa 100644 --- a/src/main/java/com/postgraduate/domain/auth/presentation/contant/AuthResponseMessage.java +++ b/src/main/java/com/postgraduate/domain/auth/presentation/contant/AuthResponseMessage.java @@ -12,6 +12,7 @@ public enum AuthResponseMessage { PERMISSION_DENIED("권한이 없습니다."), KAKAO_INVALID("카카오 정보가 유효하지 않습니다."), - KAKAO_CODE("카카오 코드가 유효하지 않습니다."); + KAKAO_CODE("카카오 코드가 유효하지 않습니다."), + FAILED_AUTH("사용자 인증에 실패했습니다."); private final String message; } diff --git a/src/main/java/com/postgraduate/global/config/security/SecurityConfig.java b/src/main/java/com/postgraduate/global/config/security/SecurityConfig.java index 0487c7bd..e2ec972e 100644 --- a/src/main/java/com/postgraduate/global/config/security/SecurityConfig.java +++ b/src/main/java/com/postgraduate/global/config/security/SecurityConfig.java @@ -1,6 +1,8 @@ package com.postgraduate.global.config.security; import com.postgraduate.domain.user.domain.entity.constant.Role; +import com.postgraduate.global.config.security.filter.CustomAccessDeniedHandler; +import com.postgraduate.global.config.security.filter.CustomAuthenticationEntryPoint; import com.postgraduate.global.config.security.jwt.JwtFilter; import com.postgraduate.global.config.security.jwt.JwtProvider; import lombok.RequiredArgsConstructor; @@ -21,8 +23,10 @@ @EnableWebSecurity @RequiredArgsConstructor public class SecurityConfig { - private final JwtProvider jwtProvider; private static final String[] PASS = {"/resource/**", "/css/**", "/js/**", "/img/**", "/lib/**"}; + private final JwtProvider jwtProvider; + private final CustomAuthenticationEntryPoint customAuthenticationEntryPoint; + private final CustomAccessDeniedHandler customAccessDeniedHandler; @Bean public BCryptPasswordEncoder encodePassword() { return new BCryptPasswordEncoder(); @@ -31,15 +35,15 @@ public BCryptPasswordEncoder encodePassword() { @Bean protected SecurityFilterChain config(HttpSecurity http) throws Exception { http - .csrf(csrf->csrf.disable()) + .csrf(csrf -> csrf.disable()) .cors(corsConfigurer -> corsConfigurer.configurationSource(source()) ) - .httpBasic(httpBasic->httpBasic.disable()) + .httpBasic(httpBasic -> httpBasic.disable()) .headers((headers) -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable)); http - .formLogin(formLogin->formLogin.disable()) - .logout(logout->logout.disable()); + .formLogin(formLogin -> formLogin.disable()) + .logout(logout -> logout.disable()); http .authorizeHttpRequests((authorize) -> authorize .requestMatchers(PASS).permitAll() @@ -48,15 +52,8 @@ protected SecurityFilterChain config(HttpSecurity http) throws Exception { ) .sessionManagement((session) -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .exceptionHandling((exceptions) -> exceptions - .authenticationEntryPoint((request, response, authException) -> { - //TODO: 인증되지 않은 유저 예외 - throw new IllegalAccessError("실패"); - }) - .accessDeniedHandler((request, response, authException) -> { - //TODO: 엑세스 거부 예외 - throw new IllegalAccessError("실패"); - - }) + .authenticationEntryPoint(customAuthenticationEntryPoint) + .accessDeniedHandler(customAccessDeniedHandler) ) .addFilterBefore(new JwtFilter(jwtProvider), UsernamePasswordAuthenticationFilter.class); diff --git a/src/main/java/com/postgraduate/global/config/security/filter/CustomAccessDeniedHandler.java b/src/main/java/com/postgraduate/global/config/security/filter/CustomAccessDeniedHandler.java new file mode 100644 index 00000000..6e0b5f9b --- /dev/null +++ b/src/main/java/com/postgraduate/global/config/security/filter/CustomAccessDeniedHandler.java @@ -0,0 +1,33 @@ +package com.postgraduate.global.config.security.filter; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.postgraduate.global.dto.ErrorResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.web.access.AccessDeniedHandler; +import org.springframework.stereotype.Component; + +import java.io.IOException; + +import static com.postgraduate.domain.auth.presentation.contant.AuthResponseCode.AUTH_DENIED; +import static com.postgraduate.domain.auth.presentation.contant.AuthResponseMessage.PERMISSION_DENIED; + +@Component +@RequiredArgsConstructor +public class CustomAccessDeniedHandler implements AccessDeniedHandler { + private final ObjectMapper objectMapper; + @Override + public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException { + response.setStatus(HttpStatus.FORBIDDEN.value()); + response.setContentType(MediaType.APPLICATION_JSON_VALUE); + response.setCharacterEncoding("UTF-8"); + objectMapper.writeValue( + response.getOutputStream(), + new ErrorResponse(AUTH_DENIED.getCode(), PERMISSION_DENIED.getMessage()) + ); + } +} diff --git a/src/main/java/com/postgraduate/global/config/security/filter/CustomAuthenticationEntryPoint.java b/src/main/java/com/postgraduate/global/config/security/filter/CustomAuthenticationEntryPoint.java new file mode 100644 index 00000000..751b7879 --- /dev/null +++ b/src/main/java/com/postgraduate/global/config/security/filter/CustomAuthenticationEntryPoint.java @@ -0,0 +1,35 @@ +package com.postgraduate.global.config.security.filter; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.postgraduate.global.dto.ErrorResponse; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + +import java.io.IOException; + +import static com.postgraduate.domain.auth.presentation.contant.AuthResponseCode.AUTH_FAILED; +import static com.postgraduate.domain.auth.presentation.contant.AuthResponseMessage.FAILED_AUTH; + +@Component +@RequiredArgsConstructor +public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint { + private final ObjectMapper objectMapper; + + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { + response.setStatus(HttpStatus.UNAUTHORIZED.value()); + response.setContentType(MediaType.APPLICATION_JSON_VALUE); + response.setCharacterEncoding("UTF-8"); + objectMapper.writeValue( + response.getOutputStream(), + new ErrorResponse(AUTH_FAILED.getCode(), FAILED_AUTH.getMessage()) + ); + } +}