Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
766511b
[chore] 인증 인가를 위한 의존성 주입 (#30)
buzz0331 Jun 27, 2025
6e6f6ee
[feat] 필요한 상수 정의 (#30)
buzz0331 Jun 27, 2025
775093a
[feat] Oauth2 응답을 파싱하기 위한 UserDetails 클래스 (#30)
buzz0331 Jun 27, 2025
c1adbeb
[feat] 인증.인가를 위한 에러 정의 및 핸들러 추가 (#30)
buzz0331 Jun 27, 2025
681c5d8
[feat] User에 Oauth2Id 컬럼 추가 (#30)
buzz0331 Jun 27, 2025
e59c1a8
[feat] JwtAuthenticationFilter(인가용 필터) 정의 (#30)
buzz0331 Jun 27, 2025
e78d5b5
[feat] 필터 예외 처리를 위한 AuthenticationEntryPoint 정의 (#30)
buzz0331 Jun 27, 2025
f768774
[feat] Oauth2User를 구현하는 클래스 선언 (#30)
buzz0331 Jun 27, 2025
291f7c9
[feat] 소셜 로그인 서비스 로직 (#30)
buzz0331 Jun 27, 2025
42d3d95
[feat] 로그인 성공시 핸들러 추가 (#30)
buzz0331 Jun 27, 2025
2b676af
[feat] Jwt 생성, 검증 등을 담당하는 클래스 선언 (#30)
buzz0331 Jun 27, 2025
8f9f88c
[feat] SecurityConfig 정의 (#30)
buzz0331 Jun 27, 2025
2c49059
[feat] 로그인한 user 정보를 담는 LoginUser (#30)
buzz0331 Jun 27, 2025
b23a6fa
[feat] 필요한 어노테이션 및 argument resolver (#30)
buzz0331 Jun 27, 2025
c776f43
[feat] argument resolver 설정 (#30)
buzz0331 Jun 27, 2025
3a7a505
[feat] 회원가입 dto에 oauth2Id 추가(#30)
buzz0331 Jun 27, 2025
4a16efb
[feat] 회원가입 로직에서 oauth2Id도 저장 (#30)
buzz0331 Jun 27, 2025
f3e16cf
[feat] 회원가입 시 임시 토큰 추출 및 액세스 토큰 발급 로직 추가 (#30)
buzz0331 Jun 27, 2025
b8f1e46
[refactor] email 컬럼 제거 (#30)
buzz0331 Jun 28, 2025
caa7452
[refactor] 필요없는 filter 설정 제거 (#30)
buzz0331 Jun 28, 2025
2da2229
[test] 팩토리 클래스 도입 (#30)
buzz0331 Jun 28, 2025
54ab951
[test] 인증인가 테스트 (#30)
buzz0331 Jun 28, 2025
800bdb0
[refactor] 상수 enum 처리 (#30)
buzz0331 Jun 28, 2025
f0003a9
[refactor] 곱하기 연산 삭제 (#30)
buzz0331 Jun 28, 2025
8510267
[feat] BookDto 작성 (#32)
hd0rable Jun 27, 2025
ecdc972
[feat] BookQueryController 구현 (#32)
hd0rable Jun 27, 2025
7b1ae2a
[feat] NaverApiUtil 구현 (#32)
hd0rable Jun 27, 2025
31b3634
[feat] NaverBookXmlParser 작성 (#32)
hd0rable Jun 27, 2025
ddf9647
[test] NaverApiUtilTest 테스트 코드 작성 (#32)
hd0rable Jun 27, 2025
943e45a
[refactor] NaverApiUtil 위치 변경 및 검색 url 환경변수 설정(#32)
hd0rable Jun 29, 2025
40c1e2a
[refactor] 테스트코드 수정 (#32)
hd0rable Jun 29, 2025
9187296
[refactor] BookDto이너클래스로 수정및 컨트롤러,서비스 response값 분리 (#32)
hd0rable Jun 29, 2025
781cc4d
[refactor] 컨트롤러 로직 수정 (#32)
hd0rable Jun 29, 2025
ad4eab1
[refactor] NaverBookParseResult 반환값 NaverBook로 수정 (#32)
hd0rable Jun 29, 2025
12c17d0
[refactor] findByOauth2Id 반환 타입 Optional로 감싸기 (#30)
buzz0331 Jun 29, 2025
adcd74a
[refactor] ArgumentResolver 타입 안정성 보장 (#30)
buzz0331 Jun 29, 2025
ca20c73
[refactor] 변수 이름 일관성 보장 (#30)
buzz0331 Jun 29, 2025
59b7bde
[refactor] 지원하지 않는 소셜 로그인 예외 처리 (#30)
buzz0331 Jun 29, 2025
0402c64
[refactor] JwtAuthenticationFilter 의존성 주입 (#30)
buzz0331 Jun 29, 2025
dba86f4
[test] BookQueryControllerTest filter 제거 (#30)
buzz0331 Jun 29, 2025
22f3edf
[refactor] : 회원가입 api request dto 수정 및 테스트 코드 수정 (#31)
seongjunnoh Jun 27, 2025
5b9ea9c
[refactor] : 테스트 메서드에 DB clear 코드 추가 (#31)
seongjunnoh Jun 27, 2025
d01a344
[feat] : 닉네임 중복 검사 api controller 구현 (#31)
seongjunnoh Jun 27, 2025
df2b46c
[feat] : 닉네임 중복 검사 영속성 어댑터 구현 (#31)
seongjunnoh Jun 27, 2025
1af9a7b
[refactor] : tearDown 메서드를 @AfterEach로 변경 (#31)
seongjunnoh Jun 27, 2025
11ef7ac
[feat] : querydsl 의존성 주입 (#31)
seongjunnoh Jun 27, 2025
b8c58f5
[refactor] : Querydsl 전용 repository 네이밍 수정 (#31)
seongjunnoh Jun 29, 2025
c2b00ea
[refactor] : request, response dto 네이밍 수정 (#31)
seongjunnoh Jun 29, 2025
9271fd4
[feat] 회원가입 시 임시 토큰 추출 및 액세스 토큰 발급 로직 추가 (#30)
buzz0331 Jun 27, 2025
50a5f32
[refactor] email 컬럼 제거 (#30)
buzz0331 Jun 28, 2025
873144a
[refactor] conflict 해결 (#30)
buzz0331 Jun 29, 2025
1c63005
[refactor] dto 컨벤션에 맞춰서 수정 (#30)
buzz0331 Jun 29, 2025
95eb446
[refactor] conflict 해결 (#30)
buzz0331 Jun 29, 2025
533775d
[refactor] conflict 해결 (#30)
buzz0331 Jun 29, 2025
458a06d
[refactor] 쓸데없는 import 및 반환형태 제거 (#30)
buzz0331 Jun 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 14 additions & 10 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,33 @@ repositories {
dependencies {
// Spring Boot 스타터
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
// implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
Comment thread
coderabbitai[bot] marked this conversation as resolved.

// Lombok
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'

//Security
implementation 'org.springframework.boot:spring-boot-starter-security'

// JWT
implementation 'io.jsonwebtoken:jjwt-api:0.12.3'
implementation 'io.jsonwebtoken:jjwt-impl:0.12.3'
implementation 'io.jsonwebtoken:jjwt-jackson:0.12.3'

// OAuth2
implementation 'org.springframework.security:spring-security-oauth2-client'

// Runtime DB 드라이버
runtimeOnly 'com.h2database:h2'
runtimeOnly 'com.mysql:mysql-connector-j'

// Test
testImplementation 'org.assertj:assertj-core:3.24.2'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
// testImplementation 'org.springframework.security:spring-security-test'
testImplementation 'org.springframework.security:spring-security-test'
testImplementation 'com.h2database:h2:2.1.214'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

Expand All @@ -55,16 +65,10 @@ dependencies {

def querydslDir = layout.buildDirectory.dir("generated/querydsl").get().asFile

// QueryDSL Q-클래스는 compileJava 단계에서만 생성
tasks.named('compileJava', org.gradle.api.tasks.compile.JavaCompile) {
tasks.withType(JavaCompile).configureEach {
options.generatedSourceOutputDirectory.set(querydslDir)
}

// test 컴파일 단계에서는 어노테이션 프로세서를 비워서 Q-클래스 중복 생성 방지
tasks.named('compileTestJava', org.gradle.api.tasks.compile.JavaCompile) {
options.annotationProcessorPath = files()
}

sourceSets {
main.java.srcDirs += [ querydslDir ]
}
Expand Down
18 changes: 18 additions & 0 deletions src/main/java/konkuk/thip/common/exception/AuthException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package konkuk.thip.common.exception;

import konkuk.thip.common.exception.code.ErrorCode;
import lombok.Getter;

@Getter
public class AuthException extends RuntimeException {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

private final ErrorCode errorCode;

public AuthException(ErrorCode errorCode) {
this.errorCode = errorCode;
}

public AuthException(ErrorCode errorCode, Exception e) {
super(e);
this.errorCode = errorCode;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ public enum ErrorCode implements ResponseCode {
API_INVALID_PARAM(HttpStatus.BAD_REQUEST, 40002, "파라미터 값 중 유효하지 않은 값이 있습니다."),
API_INVALID_TYPE(HttpStatus.BAD_REQUEST, 40003, "파라미터 타입이 잘못되었습니다."),

AUTH_INVALID_TOKEN(HttpStatus.UNAUTHORIZED, 40100, "유효하지 않은 토큰입니다."),
AUTH_EXPIRED_TOKEN(HttpStatus.UNAUTHORIZED, 40101, "만료된 토큰입니다."),
AUTH_UNAUTHORIZED(HttpStatus.UNAUTHORIZED, 40102, "인증되지 않은 사용자입니다."),
AUTH_TOKEN_NOT_FOUND(HttpStatus.UNAUTHORIZED, 40103, "토큰을 찾을 수 없습니다."),
AUTH_LOGIN_FAILED(HttpStatus.UNAUTHORIZED, 40104, "로그인에 실패했습니다."),
AUTH_UNSUPPORTED_SOCIAL_LOGIN(HttpStatus.UNAUTHORIZED, 40105, "지원하지 않는 소셜 로그인입니다."),

/* 60000부터 비즈니스 예외 */
/**
* 60000 : alias error
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package konkuk.thip.common.exception.handler;

import konkuk.thip.common.dto.ErrorResponse;
import konkuk.thip.common.exception.AuthException;
import konkuk.thip.common.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
Expand Down Expand Up @@ -71,6 +72,15 @@ public ResponseEntity<ErrorResponse> missingServletRequestParameterExceptionHand
.body(ErrorResponse.of(API_MISSING_PARAM, e.getParameterName() + "를 추가해서 요청해주세요."));
}

// 인증, 인가 권한 관련 예외 처리
@ExceptionHandler(AuthException.class)
public ResponseEntity<ErrorResponse> authExceptionHandler(AuthException e) {
log.error("[AuthExceptionHandler] {}", e.getMessage());
return ResponseEntity
.status(e.getErrorCode().getHttpStatus())
.body(ErrorResponse.of(e.getErrorCode()));
}

// 비즈니스 로직에서 발생한 예외 처리
@ExceptionHandler(BusinessException.class)
public ResponseEntity<ErrorResponse> businessExceptionHandler(BusinessException e) {
Expand All @@ -81,12 +91,21 @@ public ResponseEntity<ErrorResponse> businessExceptionHandler(BusinessException
}

// 서버 내부 오류 예외 처리
@ExceptionHandler({RuntimeException.class, IllegalStateException.class})
public ResponseEntity<ErrorResponse> runtimeExceptionHandler(Exception e) {
@ExceptionHandler(RuntimeException.class)
public ResponseEntity<ErrorResponse> runtimeExceptionHandler(RuntimeException e) {
log.error("[RuntimeExceptionHandler] {}", e.getMessage());
return ResponseEntity
.status(API_SERVER_ERROR.getHttpStatus())
.body(ErrorResponse.of(API_SERVER_ERROR));
}

// IllegalStateException 예외 처리
@ExceptionHandler(IllegalStateException.class)
public ResponseEntity<ErrorResponse> illegalStateExceptionHandler(IllegalStateException e) {
log.error("[IllegalStateExceptionHandler] {}", e.getMessage());
return ResponseEntity
.status(API_SERVER_ERROR.getHttpStatus())
.body(ErrorResponse.of(API_SERVER_ERROR));
}

}
11 changes: 11 additions & 0 deletions src/main/java/konkuk/thip/common/security/annotation/Oauth2Id.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package konkuk.thip.common.security.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface Oauth2Id {
}
11 changes: 11 additions & 0 deletions src/main/java/konkuk/thip/common/security/annotation/UserId.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package konkuk.thip.common.security.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface UserId {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package konkuk.thip.common.security.argument_resolver;

import jakarta.servlet.http.HttpServletRequest;
import konkuk.thip.common.exception.AuthException;
import konkuk.thip.common.security.annotation.Oauth2Id;
import lombok.RequiredArgsConstructor;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import static konkuk.thip.common.exception.code.ErrorCode.AUTH_TOKEN_NOT_FOUND;

@Component
@RequiredArgsConstructor
public class Oauth2IdArgumentResolver implements HandlerMethodArgumentResolver {

@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(Oauth2Id.class)
&& parameter.getParameterType().equals(String.class);
}

@Override
public String resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) {

Object oauth2Id = ((HttpServletRequest) webRequest.getNativeRequest()).getAttribute("oauth2Id");
if (oauth2Id == null) {
throw new AuthException(AUTH_TOKEN_NOT_FOUND);
}
return (String) oauth2Id;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package konkuk.thip.common.security.argument_resolver;

import jakarta.servlet.http.HttpServletRequest;
import konkuk.thip.common.exception.AuthException;
import konkuk.thip.common.security.annotation.UserId;
import lombok.RequiredArgsConstructor;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import static konkuk.thip.common.exception.code.ErrorCode.AUTH_TOKEN_NOT_FOUND;

@Component
@RequiredArgsConstructor
public class UserIdArgumentResolver implements HandlerMethodArgumentResolver {

@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(UserId.class)
&& parameter.getParameterType().equals(Long.class);
}

@Override
public Long resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) {

Object userId = ((HttpServletRequest) webRequest.getNativeRequest()).getAttribute("userId");
if (userId == null) {
throw new AuthException(AUTH_TOKEN_NOT_FOUND);
}
return (Long) userId;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package konkuk.thip.common.security.constant;

import lombok.Getter;

@Getter
public enum AuthParameters {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

와우 이거 상수로싹다 정리하신거 너뮤좋네요 💯

JWT_HEADER_KEY("Authorization"),
JWT_PREFIX("Bearer "),
KAKAO("kakao"),
GOOGLE("google"),
KAKAO_PROVIDER_ID_KEY("id"),
GOOGLE_PROVIDER_ID_KEY("sub"),
JWT_ACCESS_TOKEN_KEY("userId"),
JWT_SIGNUP_TOKEN_KEY("oauth2Id"),
;
Comment on lines +6 to +15
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! authorization 관련 string value 들을 enum으로 모아두니 관리하기 편할 것 같습니다!


private final String value;

AuthParameters(String value) {
this.value = value;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package konkuk.thip.common.security.filter;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;

import java.io.IOException;

@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
private final HandlerExceptionResolver resolver;

public JwtAuthenticationEntryPoint(@Qualifier("handlerExceptionResolver") HandlerExceptionResolver resolver){
this.resolver = resolver;
}

@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
Exception e = (Exception) request.getAttribute("exception");
if(e == null){
e = authException;
}
resolver.resolveException(request, response, null, e);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package konkuk.thip.common.security.filter;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import konkuk.thip.common.exception.AuthException;
import konkuk.thip.common.security.oauth2.CustomOAuth2User;
import konkuk.thip.common.security.oauth2.LoginUser;
import konkuk.thip.common.security.util.JwtUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

import static konkuk.thip.common.exception.code.ErrorCode.*;
import static konkuk.thip.common.security.constant.AuthParameters.*;

@Slf4j
@Component
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {

private final JwtUtil jwtUtil;

@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
try {
String token = extractToken(request);
if (token == null) {
throw new AuthException(AUTH_TOKEN_NOT_FOUND);
}

if (!jwtUtil.validateToken(token)) {
throw new AuthException(AUTH_INVALID_TOKEN);
}

if (jwtUtil.isExpired(token)) {
throw new AuthException(AUTH_EXPIRED_TOKEN);
}

LoginUser loginUser = jwtUtil.getLoginUser(token);

if (loginUser.userId() != null) {
request.setAttribute(JWT_ACCESS_TOKEN_KEY.getValue(), loginUser.userId());
}
else {
request.setAttribute(JWT_SIGNUP_TOKEN_KEY.getValue(), loginUser.oauth2Id());
}

CustomOAuth2User customOAuth2User = new CustomOAuth2User(loginUser);

Authentication authToken = new UsernamePasswordAuthenticationToken(customOAuth2User, null, customOAuth2User.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authToken);
} catch (Exception e) {
log.error("JWT 필터에서 오류 발생: {}", e.getMessage());
request.setAttribute("exception", e);
} finally {
filterChain.doFilter(request, response);
}
Comment on lines +62 to +67
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

예외 처리 시 보안 정보 노출을 주의해야 합니다.

로그에 전체 예외 메시지를 출력하면 민감한 정보가 노출될 수 있습니다.

 } catch (Exception e) {
-    log.error("JWT 필터에서 오류 발생: {}", e.getMessage());
+    log.error("JWT 필터에서 오류 발생", e);
     request.setAttribute("exception", e);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} catch (Exception e) {
log.error("JWT 필터에서 오류 발생: {}", e.getMessage());
request.setAttribute("exception", e);
} finally {
filterChain.doFilter(request, response);
}
} catch (Exception e) {
log.error("JWT 필터에서 오류 발생", e);
request.setAttribute("exception", e);
} finally {
filterChain.doFilter(request, response);
}
🤖 Prompt for AI Agents
In src/main/java/konkuk/thip/common/security/filter/JwtAuthenticationFilter.java
around lines 62 to 67, the current exception logging outputs the full exception
message, which may expose sensitive information. Modify the log statement to
avoid printing detailed exception messages; instead, log a generic error message
or only the exception type without sensitive details. This prevents potential
security risks from information leakage in logs.

}

private String extractToken(HttpServletRequest request) {
String authorization = request.getHeader(JWT_HEADER_KEY.getValue());
if (authorization != null && authorization.startsWith(JWT_PREFIX.getValue())) {
return authorization.split(" ")[1];
}
log.info("토큰이 없습니다.");
return null;
}
Comment on lines +70 to +77
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

토큰 추출 로직을 개선할 수 있습니다.

현재 구현에서 잠재적인 ArrayIndexOutOfBoundsException이 발생할 수 있습니다.

 private String extractToken(HttpServletRequest request) {
     String authorization = request.getHeader(JWT_HEADER_KEY.getValue());
-    if (authorization != null && authorization.startsWith(JWT_PREFIX.getValue())) {
-        return authorization.split(" ")[1];
+    if (authorization != null && authorization.startsWith(JWT_PREFIX.getValue())) {
+        String[] parts = authorization.split(" ");
+        if (parts.length == 2) {
+            return parts[1];
+        }
     }
     log.info("토큰이 없습니다.");
     return null;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private String extractToken(HttpServletRequest request) {
String authorization = request.getHeader(JWT_HEADER_KEY.getValue());
if (authorization != null && authorization.startsWith(JWT_PREFIX.getValue())) {
return authorization.split(" ")[1];
}
log.info("토큰이 없습니다.");
return null;
}
private String extractToken(HttpServletRequest request) {
String authorization = request.getHeader(JWT_HEADER_KEY.getValue());
if (authorization != null && authorization.startsWith(JWT_PREFIX.getValue())) {
String[] parts = authorization.split(" ");
if (parts.length == 2) {
return parts[1];
}
}
log.info("토큰이 없습니다.");
return null;
}
🤖 Prompt for AI Agents
In src/main/java/konkuk/thip/common/security/filter/JwtAuthenticationFilter.java
around lines 70 to 77, the extractToken method may throw an
ArrayIndexOutOfBoundsException when splitting the authorization header if the
token part is missing. To fix this, add a check to ensure the split array has
the expected length before accessing the token element, and handle cases where
the token is absent more safely.


}
Loading