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
21 changes: 21 additions & 0 deletions src/main/java/run/backend/domain/auth/exception/AuthErrorCode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package run.backend.domain.auth.exception;

import lombok.AllArgsConstructor;
import lombok.Getter;
import run.backend.global.exception.ErrorCode;

@Getter
@AllArgsConstructor
public enum AuthErrorCode implements ErrorCode {

INVALID_SIGNUP_TOKEN(3001, "유효하지 않은 가입 토큰입니다."),
USER_ALREADY_EXISTS(3002, "이미 가입된 사용자입니다."),
OAUTH_REQUEST_FAILED(3003, "외부 인증 서버와 통신 중 오류가 발생했습니다."),
TOKEN_MISSING_AUTHORITY(3004, "토큰에 권한 정보가 없습니다."),
INVALID_REFRESH_TOKEN(3005, "유효하지 않은 리프레시 토큰입니다."),
REFRESH_TOKEN_NOT_FOUND(3006, "리프레시 토큰을 찾을 수 없습니다."),
REFRESH_TOKEN_EXPIRED(3007, "리프레시 토큰이 만료되었습니다.");

private final int errorCode;
private final String errorMessage;
}
52 changes: 52 additions & 0 deletions src/main/java/run/backend/domain/auth/exception/AuthException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package run.backend.domain.auth.exception;

import run.backend.global.exception.CustomException;

public class AuthException extends CustomException {

public AuthException(final AuthErrorCode authErrorCode) {
super(authErrorCode);
}

public static class InvalidSignupToken extends AuthException {
public InvalidSignupToken() {
super(AuthErrorCode.INVALID_SIGNUP_TOKEN);
}
}

public static class UserAlreadyExists extends AuthException {
public UserAlreadyExists() {
super(AuthErrorCode.USER_ALREADY_EXISTS);
}
}

public static class OauthRequestFailed extends AuthException {
public OauthRequestFailed() {
super(AuthErrorCode.OAUTH_REQUEST_FAILED);
}
}

public static class TokenMissingAuthority extends AuthException {
public TokenMissingAuthority() {
super(AuthErrorCode.TOKEN_MISSING_AUTHORITY);
}
}

public static class InvalidRefreshToken extends AuthException {
public InvalidRefreshToken() {
super(AuthErrorCode.INVALID_REFRESH_TOKEN);
}
}

public static class RefreshTokenNotFound extends AuthException {
public RefreshTokenNotFound() {
super(AuthErrorCode.REFRESH_TOKEN_NOT_FOUND);
}
}

public static class RefreshTokenExpired extends AuthException {
public RefreshTokenExpired() {
super(AuthErrorCode.REFRESH_TOKEN_EXPIRED);
}
}
}
20 changes: 9 additions & 11 deletions src/main/java/run/backend/domain/auth/service/AuthService.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,11 @@
import run.backend.domain.auth.dto.response.SignupResponse;
import run.backend.domain.auth.dto.response.TokenResponse;
import run.backend.domain.auth.entity.RefreshToken;
import run.backend.domain.auth.exception.AuthException;
import run.backend.domain.auth.repository.RefreshTokenRepository;
import run.backend.domain.member.entity.Member;
import run.backend.domain.member.enums.OAuthType;
import run.backend.domain.member.enums.Role;
import run.backend.domain.member.repository.MemberRepository;
import run.backend.global.exception.ApplicationException;
import run.backend.global.exception.ExceptionCode;
import run.backend.global.oauth2.OAuth2UserInfo;
import run.backend.global.oauth2.OAuth2UserInfoFactory;
import run.backend.global.security.CustomUserDetails;
Expand Down Expand Up @@ -76,7 +74,7 @@ public SignupResponse socialLogin(String providerName, String authorizationCode)

public TokenResponse completeSignup(SignupRequest signupRequest, MultipartFile profileImage) {
if (!jwtTokenProvider.validateToken(signupRequest.signupToken())) {
throw new ApplicationException(ExceptionCode.INVALID_SIGNUP_TOKEN);
throw new AuthException.InvalidSignupToken();
}

Claims claims = jwtTokenProvider.parseClaims(signupRequest.signupToken());
Expand All @@ -86,7 +84,7 @@ public TokenResponse completeSignup(SignupRequest signupRequest, MultipartFile p
String name = claims.get("name", String.class);

memberRepository.findByOauthId(oauthId).ifPresent(m -> {
throw new ApplicationException(ExceptionCode.USER_ALREADY_EXISTS);
throw new AuthException.UserAlreadyExists();
});

String profileImageName = fileService.saveProfileImage(profileImage);
Expand Down Expand Up @@ -129,7 +127,7 @@ private String getAccessToken(String authorizationCode, ClientRegistration provi
ResponseEntity<String> response = restTemplate.postForEntity(tokenUri, request, String.class);
Map<String, Object> responseBody = objectMapper.readValue(response.getBody(), new TypeReference<>() {});
return (String) responseBody.get("access_token");
} catch (Exception e) { throw new ApplicationException(ExceptionCode.OAUTH_REQUEST_FAILED); }
} catch (Exception e) { throw new AuthException.OauthRequestFailed(); }
}

private Map<String, Object> getUserAttributes(String accessToken, ClientRegistration provider) {
Expand All @@ -140,21 +138,21 @@ private Map<String, Object> getUserAttributes(String accessToken, ClientRegistra
try {
ResponseEntity<String> response = restTemplate.exchange(userInfoUri, HttpMethod.GET, request, String.class);
return objectMapper.readValue(response.getBody(), new TypeReference<>() {});
} catch (Exception e) { throw new ApplicationException(ExceptionCode.OAUTH_REQUEST_FAILED); }
} catch (Exception e) { throw new AuthException.OauthRequestFailed(); }
}

public TokenResponse refreshTokens(String authorizationCode) {
String refreshToken = extractTokenFromHeader(authorizationCode);

if (!jwtTokenProvider.validateToken(refreshToken)) {
throw new ApplicationException(ExceptionCode.INVALID_REFRESH_TOKEN);
throw new AuthException.InvalidRefreshToken();
}

RefreshToken refreshTokenEntity = refreshTokenRepository.findByToken(refreshToken)
.orElseThrow(() -> new ApplicationException(ExceptionCode.REFRESH_TOKEN_NOT_FOUND));
.orElseThrow(AuthException.RefreshTokenNotFound::new);

if (refreshTokenEntity.isExpired()) {
throw new ApplicationException(ExceptionCode.REFRESH_TOKEN_EXPIRED);
throw new AuthException.RefreshTokenExpired();
}

Member member = refreshTokenEntity.getMember();
Expand All @@ -180,7 +178,7 @@ private void saveRefreshToken(String refreshToken, Member member) {

private String extractTokenFromHeader(String authorizationHeader) {
if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer ")) {
throw new ApplicationException(ExceptionCode.INVALID_REFRESH_TOKEN);
throw new AuthException.InvalidRefreshToken();
}
return authorizationHeader.substring(7);
}
Expand Down
20 changes: 20 additions & 0 deletions src/main/java/run/backend/domain/file/exception/FileErrorCode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package run.backend.domain.file.exception;

import lombok.AllArgsConstructor;
import lombok.Getter;
import run.backend.global.exception.ErrorCode;

@Getter
@AllArgsConstructor
public enum FileErrorCode implements ErrorCode {

FILE_UPLOAD_FAILED(4001, "파일 업로드에 실패했습니다."),
FILE_SIZE_EXCEEDED(4002, "파일 크기가 10MB를 초과합니다."),
INVALID_FILE_NAME(4003, "유효하지 않은 파일명입니다."),
INVALID_FILE_EXTENSION(4004, "지원하지 않는 파일 형식입니다. (jpg, jpeg, png, gif만 허용)"),
INVALID_FILE_TYPE(4005, "이미지 파일만 업로드 가능합니다."),
FILE_NOT_FOUND(4006, "파일을 찾을 수 없습니다.");

private final int errorCode;
private final String errorMessage;
}
46 changes: 46 additions & 0 deletions src/main/java/run/backend/domain/file/exception/FileException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package run.backend.domain.file.exception;

import run.backend.global.exception.CustomException;

public class FileException extends CustomException {

public FileException(final FileErrorCode fileErrorCode) {
super(fileErrorCode);
}

public static class FileUploadFailed extends FileException {
public FileUploadFailed() {
super(FileErrorCode.FILE_UPLOAD_FAILED);
}
}

public static class FileSizeExceeded extends FileException {
public FileSizeExceeded() {
super(FileErrorCode.FILE_SIZE_EXCEEDED);
}
}

public static class InvalidFileName extends FileException {
public InvalidFileName() {
super(FileErrorCode.INVALID_FILE_NAME);
}
}

public static class InvalidFileExtension extends FileException {
public InvalidFileExtension() {
super(FileErrorCode.INVALID_FILE_EXTENSION);
}
}

public static class InvalidFileType extends FileException {
public InvalidFileType() {
super(FileErrorCode.INVALID_FILE_TYPE);
}
}

public static class FileNotFound extends FileException {
public FileNotFound() {
super(FileErrorCode.FILE_NOT_FOUND);
}
}
}
21 changes: 10 additions & 11 deletions src/main/java/run/backend/domain/file/service/FileService.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import run.backend.global.exception.ApplicationException;
import run.backend.global.exception.ExceptionCode;
import run.backend.domain.file.exception.FileException;

import java.io.IOException;
import java.net.MalformedURLException;
Expand Down Expand Up @@ -53,7 +52,7 @@ public String saveProfileImage(MultipartFile file) {
return newFilename;

} catch (IOException e) {
throw new ApplicationException(ExceptionCode.FILE_UPLOAD_FAILED);
throw new FileException.FileUploadFailed();
}
}

Expand All @@ -67,13 +66,13 @@ public Resource getFileResource(String filename) {
Resource resource = new UrlResource(filePath.toUri());

if (!resource.exists() || !resource.isReadable()) {
throw new ApplicationException(ExceptionCode.FILE_NOT_FOUND);
throw new FileException.FileNotFound();
}

return resource;

} catch (MalformedURLException e) {
throw new ApplicationException(ExceptionCode.FILE_NOT_FOUND);
throw new FileException.FileNotFound();
}
}

Expand All @@ -94,32 +93,32 @@ public String getContentType(String filename) {

private void validateFile(MultipartFile file) {
if (file.getSize() > MAX_FILE_SIZE) {
throw new ApplicationException(ExceptionCode.FILE_SIZE_EXCEEDED);
throw new FileException.FileSizeExceeded();
}

String contentType = file.getContentType();
if (contentType == null || !contentType.startsWith("image/")) {
throw new ApplicationException(ExceptionCode.INVALID_FILE_TYPE);
throw new FileException.InvalidFileType();
}

String originalFilename = file.getOriginalFilename();
if (originalFilename == null || originalFilename.isEmpty()) {
throw new ApplicationException(ExceptionCode.INVALID_FILE_NAME);
throw new FileException.InvalidFileName();
}

String extension = getFileExtension(originalFilename);
if (!ALLOWED_EXTENSIONS.contains(extension.toLowerCase())) {
throw new ApplicationException(ExceptionCode.INVALID_FILE_EXTENSION);
throw new FileException.InvalidFileExtension();
}
}

private void validateFilename(String filename) {
if (filename == null || filename.trim().isEmpty()) {
throw new ApplicationException(ExceptionCode.INVALID_FILE_NAME);
throw new FileException.InvalidFileName();
}

if (!filename.matches("^[a-fA-F0-9-]+\\.(jpg|jpeg|png|gif)$")) {
throw new ApplicationException(ExceptionCode.INVALID_FILE_NAME);
throw new FileException.InvalidFileName();
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package run.backend.global.common.response;

import com.fasterxml.jackson.annotation.JsonFormat;
import run.backend.global.exception.ExceptionCode;
import run.backend.global.exception.ErrorCode;

import java.time.LocalDateTime;

Expand All @@ -24,7 +24,7 @@ public CommonResponse(String message) {
}

// api 응답이 실패인 경우
public CommonResponse(ExceptionCode exceptionCode) {
this(LocalDateTime.now(), exceptionCode.getCode(), exceptionCode.getMessage(), null);
public CommonResponse(int errorCode, String errorMessage) {
this(LocalDateTime.now(), errorCode, errorMessage, null);
}
}

This file was deleted.

23 changes: 23 additions & 0 deletions src/main/java/run/backend/global/exception/CustomException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package run.backend.global.exception;

import lombok.Getter;

@Getter
public class CustomException extends RuntimeException {

private final int errorCode;
private final String errorMessage;

public <T extends Enum<T> & ErrorCode> CustomException(final T errorType) {
errorCode = errorType.getErrorCode();
errorMessage = errorType.getErrorMessage();
}

@Override
public String toString() {

return String.format("errorCode=%d | errorMessage=%s",
errorCode,
errorMessage );
}
}
7 changes: 7 additions & 0 deletions src/main/java/run/backend/global/exception/ErrorCode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package run.backend.global.exception;

public interface ErrorCode {

int getErrorCode();
String getErrorMessage();
}
Loading