Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import life.mosu.mosuserver.domain.user.entity.UserJpaEntity;
import life.mosu.mosuserver.domain.user.entity.UserRole;
import life.mosu.mosuserver.domain.user.repository.UserJpaRepository;
import life.mosu.mosuserver.global.exception.OAuthException;
import life.mosu.mosuserver.global.processor.StepProcessor;
import life.mosu.mosuserver.global.util.PhoneNumberUtil;
import lombok.RequiredArgsConstructor;
Expand All @@ -28,9 +29,9 @@ public UserJpaEntity process(final OAuthUserInfo info) {
return userRepository.findByPhoneNumber(
PhoneNumberUtil.formatPhoneNumber(info.phoneNumber()))
.map(existingUser -> {
// if (existingUser.isMosuUser()) {
// throw new IllegalArgumentException("이미 모수 회원입니다.");
// }
if (existingUser.isMosuUser()) {
throw new OAuthException("DUPLICATE");
}
existingUser.updateOAuthUser(
info.gender(),
info.name(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package life.mosu.mosuserver.global.exception;

import org.springframework.security.core.AuthenticationException;

public class OAuthException extends AuthenticationException {

public OAuthException(String msg) {
super(msg);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import life.mosu.mosuserver.presentation.auth.dto.request.LoginResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.AuthenticationException;
Expand All @@ -27,8 +26,11 @@ public class OAuth2LoginFailureHandler implements
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {

LoginResponse loginResponse = LoginResponse.from();
String jsonResponse = UriUtils.encode(objectMapper.writeValueAsString(loginResponse),
OAuthErrorType errorType = OAuthErrorType.from(exception.getMessage());
OAuthFailureResponse oAuthFailureResponse = OAuthFailureResponse.from(
errorType.getMessage());

String jsonResponse = UriUtils.encode(objectMapper.writeValueAsString(oAuthFailureResponse),
StandardCharsets.UTF_8);

final String redirectWithAccessToken = UriComponentsBuilder.fromUriString(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package life.mosu.mosuserver.global.handler;

import lombok.Getter;

@Getter
public enum OAuthErrorType {
CANCELED("CANCELED"),
DUPLICATE("DUPLICATE"),
UNKNOWN("UNKNOWN");

private final String message;

OAuthErrorType(String message) {
this.message = message;
}

public static OAuthErrorType from(String text) {
if (text == null) {
return UNKNOWN;
}
return switch (text) {
case "DUPLICATE" -> DUPLICATE;
case "[access_denied] User denied access" -> CANCELED;
default -> UNKNOWN;
};
Comment on lines +21 to +25

Choose a reason for hiding this comment

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

high

현재 from 메소드는 예외 메시지 문자열 "[access_denied] User denied access"에 직접 의존하고 있어, Spring Security 버전 변경 등에 따라 메시지가 바뀌면 코드가 오작동할 위험이 있습니다. 보다 안정적인 방법은 OAuth2LoginFailureHandler에서 exception 객체의 타입을 확인하여 OAuth2AuthenticationException인 경우 getError().getErrorCode()를 통해 access_denied와 같은 에러 코드를 얻어오고, 그 코드를 이 from 메소드에 전달하는 것입니다. 이렇게 하면 외부 라이브러리의 메시지 변경에 영향을 받지 않는 견고한 코드를 만들 수 있습니다.

아래와 같이 from 메소드를 수정하고, OAuth2LoginFailureHandler도 함께 수정하는 것을 권장합니다.

OAuth2LoginFailureHandler.java 수정 예시:

String message = exception.getMessage();
if (exception instanceof org.springframework.security.oauth2.core.OAuth2AuthenticationException e) {
    message = e.getError().getErrorCode();
}
OAuthErrorType errorType = OAuthErrorType.from(message);
Suggested change
return switch (text) {
case "DUPLICATE" -> DUPLICATE;
case "[access_denied] User denied access" -> CANCELED;
default -> UNKNOWN;
};
return switch (text) {
case "DUPLICATE" -> DUPLICATE;
case "access_denied" -> CANCELED;
default -> UNKNOWN;
};

}
}

Choose a reason for hiding this comment

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

medium

파일의 끝에 개행 문자가 없습니다. Java 코드 컨벤션 및 일부 도구와의 호환성을 위해 파일 끝에 개행 문자를 추가하는 것이 좋습니다.

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package life.mosu.mosuserver.global.handler;

public record OAuthFailureResponse(
Boolean isProfileRegistered,
String errorCode
) {

public static OAuthFailureResponse from(String errorCode) {
return new OAuthFailureResponse(null, errorCode);
}
Comment on lines +8 to +10

Choose a reason for hiding this comment

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

medium

isProfileRegistered 필드에 null을 반환하는 것은 클라이언트 측에서 NullPointerException을 유발할 수 있습니다. 로그인 실패 시에는 프로필이 등록되지 않은 상태이므로, null 대신 false를 명시적으로 반환하여 API 응답의 명확성을 높이고 잠재적인 오류를 방지하는 것이 좋습니다.

Suggested change
public static OAuthFailureResponse from(String errorCode) {
return new OAuthFailureResponse(null, errorCode);
}
public static OAuthFailureResponse from(String errorCode) {
return new OAuthFailureResponse(false, errorCode);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,4 @@ public static LoginResponse from(Boolean isProfileRegistered, final UserJpaEntit
}
return new LoginResponse(false, LoginUserResponse.from(user));
}

public static LoginResponse from() {
return new LoginResponse(null, null);
}
}