diff --git a/src/main/java/com/writon/admin/domain/service/AuthService.java b/src/main/java/com/writon/admin/domain/service/AuthService.java index 2c0265d..32ed244 100644 --- a/src/main/java/com/writon/admin/domain/service/AuthService.java +++ b/src/main/java/com/writon/admin/domain/service/AuthService.java @@ -21,6 +21,9 @@ import java.util.List; import java.util.Optional; import lombok.RequiredArgsConstructor; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.DisabledException; +import org.springframework.security.authentication.LockedException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.core.Authentication; @@ -63,9 +66,18 @@ public LoginResponseDto login(LoginRequestDto loginRequestDto) { // 2. 실제로 검증 (사용자 비밀번호 체크) 이 이루어지는 부분 // authenticate 메서드가 실행이 될 때 CustomUserDetailsService 에서 만들었던 loadUserByUsername 메서드가 실행됨 - Authentication authentication = authenticationManagerBuilder.getObject() - .authenticate(authenticationToken); - String identifier = authentication.getName(); + String identifier; + try { + Authentication authentication = authenticationManagerBuilder.getObject() + .authenticate(authenticationToken); + identifier = authentication.getName(); + } catch (BadCredentialsException e) { + throw new CustomException(ErrorCode.BAD_CREDENTIAL_ACCESS); + } catch (DisabledException e) { + throw new CustomException(ErrorCode.DISABLED_USER); + } catch (LockedException e) { + throw new CustomException(ErrorCode.LOCKED_USER); + } // 3. 인증 정보를 기반으로 JWT 토큰 생성 TokenDto tokenDto = tokenProvider.createToken(identifier); diff --git a/src/main/java/com/writon/admin/global/config/auth/JwtAuthenticationEntryPoint.java b/src/main/java/com/writon/admin/global/config/auth/JwtAuthenticationEntryPoint.java index 5bea114..d21b980 100644 --- a/src/main/java/com/writon/admin/global/config/auth/JwtAuthenticationEntryPoint.java +++ b/src/main/java/com/writon/admin/global/config/auth/JwtAuthenticationEntryPoint.java @@ -37,8 +37,8 @@ public void commence( errorCode = ErrorCode.REFRESH_TOKEN_EXPIRATION; } - if (exception.equals(ErrorCode.NOT_CORRECT_USER.getCode())) { - errorCode = ErrorCode.NOT_CORRECT_USER; + if (exception.equals(ErrorCode.UNAUTHORIZED_TOKEN.getCode())) { + errorCode = ErrorCode.UNAUTHORIZED_TOKEN; } } diff --git a/src/main/java/com/writon/admin/global/config/auth/JwtFilter.java b/src/main/java/com/writon/admin/global/config/auth/JwtFilter.java index 09b6d35..5e86e9c 100644 --- a/src/main/java/com/writon/admin/global/config/auth/JwtFilter.java +++ b/src/main/java/com/writon/admin/global/config/auth/JwtFilter.java @@ -8,6 +8,8 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; +import java.util.Arrays; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.security.core.Authentication; @@ -24,6 +26,14 @@ public class JwtFilter extends OncePerRequestFilter { private final TokenProvider tokenProvider; private final RedisTemplate redisTemplate; private final ExceptionResponseHandler exceptionResponseHandler = new ExceptionResponseHandler(); + private final List excludedPaths = Arrays.asList("/auth/login","/auth/signup"); + + @Override + protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException{ + // 로그인, 회원가입 API URL이 포함되는지 확인하는 함수 + String path = request.getRequestURI(); + return excludedPaths.stream().anyMatch(path::equals); + } // 실제 필터링 로직은 doFilterInternal 에 들어감 // JWT 토큰의 인증 정보를 현재 쓰레드의 SecurityContext 에 저장하는 역할 수행 @@ -38,7 +48,7 @@ protected void doFilterInternal( String jwt = resolveToken(request); // 2. 토큰의 존재여부 & accessToken 유효성 검사 - if (tokenProvider.validateToken(jwt, request) && StringUtils.hasText(jwt)) { + if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt, request)) { System.out.println("JWT Token 검증 통과"); // 3. 로그아웃 유저 확인 (access: O, refresh: X) diff --git a/src/main/java/com/writon/admin/global/config/auth/TokenProvider.java b/src/main/java/com/writon/admin/global/config/auth/TokenProvider.java index af03bd6..6ab6a6a 100644 --- a/src/main/java/com/writon/admin/global/config/auth/TokenProvider.java +++ b/src/main/java/com/writon/admin/global/config/auth/TokenProvider.java @@ -139,8 +139,8 @@ public boolean validateToken(String token, HttpServletRequest request) { } catch (UnsupportedJwtException e) { log.info("지원되지 않는 JWT 토큰입니다."); } catch (IllegalArgumentException e) { - log.info("아이디나 비밀번호가 잘못되었습니다"); - request.setAttribute("exception", ErrorCode.NOT_CORRECT_USER.getCode()); + log.info("JWT 토큰이 잘못되었습니다."); + request.setAttribute("exception", ErrorCode.UNAUTHORIZED_TOKEN.getCode()); } return false; } diff --git a/src/main/java/com/writon/admin/global/error/ErrorCode.java b/src/main/java/com/writon/admin/global/error/ErrorCode.java index de053f1..f4f3e30 100644 --- a/src/main/java/com/writon/admin/global/error/ErrorCode.java +++ b/src/main/java/com/writon/admin/global/error/ErrorCode.java @@ -13,7 +13,7 @@ public enum ErrorCode { BAD_REQUEST(HttpStatus.BAD_REQUEST, "400", "잘못된 요청입니다"), // 400 Bad Request UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "401", "권한이 없습니다"), // 401 Unauthorized FORBIDDEN(HttpStatus.FORBIDDEN, "403", "잘못된 요청입니다"), // 403 Forbidden - NOT_FOUND(HttpStatus.NOT_FOUND, "404", "사용자를 찾을 수 없습니다"), // 404 Not Found + NOT_FOUND(HttpStatus.NOT_FOUND, "404", "정보를 찾을 수 없습니다"), // 404 Not Found METHOD_NOT_ALLOWED(HttpStatus.METHOD_NOT_ALLOWED, "405", "허용되지 않은 메소드입니다"), // 405 Method Not Allowed CONFLICT(HttpStatus.CONFLICT, "409", "이미 가입한 사용자입니다"), // 409 Conflict INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "500", "서버에 오류가 발생하였습니다"), // 500 Internal Server Error @@ -21,10 +21,13 @@ public enum ErrorCode { // auth USER_NOT_FOUND(HttpStatus.NOT_FOUND, "A01", "사용자를 찾을 수 없습니다"), - NOT_CORRECT_USER(HttpStatus.BAD_REQUEST, "A02", "아이디나 비밀번호가 잘못되었습니다"), + UNAUTHORIZED_TOKEN(HttpStatus.UNAUTHORIZED, "A02", "권한이 없는 토큰입니다"), REFRESH_TOKEN_EXPIRATION(HttpStatus.UNAUTHORIZED, "A03", "만료된 토큰입니다"), ACCESS_TOKEN_EXPIRATION(HttpStatus.UNAUTHORIZED, "A04", "토큰 재발급을 요청해주세요"), REFRESH_TOKEN_INCONSISTENCY(HttpStatus.NOT_FOUND, "A05", "토큰이 일치하지 않습니다"), + BAD_CREDENTIAL_ACCESS(HttpStatus.BAD_REQUEST, "A06", "아이디 혹은 비밀번호가 잘못되었습니다"), + DISABLED_USER(HttpStatus.NOT_FOUND, "A07", "비활성화된 계정입니다"), + LOCKED_USER(HttpStatus.NOT_FOUND, "A08", "계정이 잠겨 있습니다"), // organization ORGANIZATION_NOT_FOUND(HttpStatus.NOT_FOUND, "O01", "조직 정보를 찾을 수 없습니다"),