Skip to content
Open
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
10 changes: 10 additions & 0 deletions oldYoung/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ dependencies {
//Spring 의존성
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
testImplementation 'org.springframework.boot:spring-boot-starter-test'

//SpringSecurity
Expand All @@ -40,6 +42,14 @@ dependencies {

//DB
runtimeOnly 'org.postgresql:postgresql'

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

//Swagger
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.0'
}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.app.oldYoung.domain.entitlement.entity;

import com.app.oldYoung.global.common.BaseEntity;
import com.app.oldYoung.global.common.entity.BaseEntity;
import com.app.oldYoung.domain.user.entity.User;
import jakarta.persistence.*;
import lombok.AccessLevel;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.app.oldYoung.domain.harume.entity;

import com.app.oldYoung.global.common.BaseEntity;
import com.app.oldYoung.global.common.entity.BaseEntity;
import com.app.oldYoung.domain.user.entity.User;
import jakarta.persistence.*;
import lombok.AccessLevel;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.app.oldYoung.domain.incomebracket.entity;

import com.app.oldYoung.domain.user.entity.User;
import com.app.oldYoung.global.common.BaseEntity;
import com.app.oldYoung.global.common.entity.BaseEntity;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Getter;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.app.oldYoung.domain.incomesnapshot.entity;

import com.app.oldYoung.domain.user.entity.User;
import com.app.oldYoung.global.common.BaseEntity;
import com.app.oldYoung.global.common.entity.BaseEntity;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Getter;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.app.oldYoung.domain.user.controller;

import com.app.oldYoung.domain.user.converter.UserConverter;
import com.app.oldYoung.domain.user.dto.UserRequestDTO;
import com.app.oldYoung.domain.user.dto.UserResponseDTO;
import com.app.oldYoung.domain.user.entity.User;
import com.app.oldYoung.global.common.apiResponse.response.ApiResponse;
import com.app.oldYoung.global.security.service.AuthService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api")
public class AuthController {

private final AuthService authService;

/**
* 소셜 로그인 통합 엔드포인트
* @param provider 'kakao', 'google' 등 소셜 로그인 제공자
* @param accessCode 각 소셜 로그인 제공자로부터 받은 인가 코드
* @return 로그인 또는 회원가입 결과
*/
@GetMapping("/auth/login/{provider}")
public ResponseEntity<ApiResponse<UserResponseDTO.JoinResultDTO>> socialLogin(
@PathVariable("provider") String provider,
@RequestParam("code") String accessCode,
HttpServletResponse httpServletResponse) {
User user = authService.oAuthLogin(provider, accessCode, httpServletResponse);
UserResponseDTO.JoinResultDTO result = UserConverter.toJoinResultDTO(user);
return ResponseEntity.ok(ApiResponse.success(result));
}

@PostMapping("/auth/reissue")
public ResponseEntity<?> reissueToken(HttpServletRequest request, HttpServletResponse response) {
authService.reissueToken(request, response);
return ResponseEntity.ok(ApiResponse.success("토큰이 성공적으로 재발급되었습니다."));
}

@PostMapping("/auth/logout")
public ResponseEntity<?> logout(HttpServletRequest request, HttpServletResponse response) {
authService.logout(request, response);
return ResponseEntity.ok(ApiResponse.success("로그아웃이 성공적으로 처리되었습니다."));
}

@PostMapping("/auth/logout/all")
public ResponseEntity<?> logoutAll(@RequestParam String email, HttpServletResponse response) {
authService.logoutAll(email, response);
return ResponseEntity.ok(ApiResponse.success("모든 기기에서 로그아웃이 처리되었습니다."));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.app.oldYoung.domain.user.controller;

import com.app.oldYoung.global.common.apiResponse.response.ApiResponse;
import com.app.oldYoung.global.security.dto.UserPrincipal;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/api/user")
@RequiredArgsConstructor
public class UserController {

/**
* 현재 로그인한 사용자 정보 조회
*/
@GetMapping("/me")
public ResponseEntity<?> getCurrentUser(@AuthenticationPrincipal UserPrincipal userPrincipal) {
Map<String, Object> currentUser = new HashMap<>();
currentUser.put("id", userPrincipal.getId());
currentUser.put("email", userPrincipal.getEmail());
currentUser.put("membername", userPrincipal.getMembername());

return ResponseEntity.ok(ApiResponse.success(currentUser));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.app.oldYoung.domain.user.converter;

import com.app.oldYoung.domain.user.dto.UserResponseDTO;
import com.app.oldYoung.domain.user.entity.User;

public class UserConverter {

public static UserResponseDTO.JoinResultDTO toJoinResultDTO(User user) {
return UserResponseDTO.JoinResultDTO.builder()
.userId(user.getId())
.email(user.getEmail())
.membername(user.getMembername())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.app.oldYoung.domain.user.dto;

import lombok.Getter;
import lombok.NoArgsConstructor;

public class UserRequestDTO {

@Getter
@NoArgsConstructor
public static class LoginRequestDTO {

private String email;

private String password;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.app.oldYoung.domain.user.dto;

import lombok.Builder;
import lombok.Getter;

public class UserResponseDTO {

@Getter
@Builder
public static class JoinResultDTO {

private Long userId;

private String email;

private String membername;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
import com.app.oldYoung.domain.harume.entity.Harume;
import com.app.oldYoung.domain.incomebracket.entity.IncomeBracket;
import com.app.oldYoung.domain.incomesnapshot.entity.IncomeSnapshot;
import com.app.oldYoung.global.common.BaseEntity;
import com.app.oldYoung.global.common.entity.BaseEntity;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

Expand Down Expand Up @@ -34,6 +35,15 @@ public class User extends BaseEntity {
@Column(name = "email")
private String email;

@Column(name = "password")
private String password;

@Column(name = "provider")
private String provider;

@Column(name = "provider_id")
private String providerId;

@OneToOne(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private IncomeBracket incomeBracket;

Expand All @@ -45,4 +55,13 @@ public class User extends BaseEntity {

@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Entitlement> entitlements;

@Builder
public User(String membername, String email, String password, String provider, String providerId) {
this.membername = membername;
this.email = email;
this.password = password;
this.provider = provider;
this.providerId = providerId;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.app.oldYoung.domain.user.repository;

import com.app.oldYoung.domain.user.entity.User;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {

Optional<User> findByEmail(String email);

Optional<User> findByProviderAndProviderId(String provider, String providerId);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.app.oldYoung.global.exception;
package com.app.oldYoung.global.common.apiResponse.exception;

import lombok.Getter;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,35 +1,44 @@
package com.app.oldYoung.global.exception;
package com.app.oldYoung.global.common.apiResponse.exception;

import lombok.Getter;
import org.springframework.http.HttpStatus;

@Getter
public enum ErrorCode {

// System Errors (E100~E199)
INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "E100", "서버 내부 오류가 발생했습니다."),
DATABASE_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "E101", "데이터베이스 오류가 발생했습니다."),

PARSING_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "E102", "데이터 파싱 중 오류가 발생했습니다."),

// Validation Errors (E200~E299)
INVALID_INPUT_VALUE(HttpStatus.BAD_REQUEST, "E200", "입력값이 올바르지 않습니다."),
MISSING_REQUEST_PARAMETER(HttpStatus.BAD_REQUEST, "E201", "필수 파라미터가 누락되었습니다."),
INVALID_TYPE_VALUE(HttpStatus.BAD_REQUEST, "E202", "데이터 타입이 올바르지 않습니다."),
INVALID_FORMAT(HttpStatus.BAD_REQUEST, "E203", "데이터 형식이 올바르지 않습니다."),

// Authentication & Authorization Errors (E300~E399)
UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "E300", "인증이 필요합니다."),
ACCESS_DENIED(HttpStatus.FORBIDDEN, "E301", "접근 권한이 없습니다."),

OAUTH_TOKEN_REQUEST_FAILED(HttpStatus.INTERNAL_SERVER_ERROR, "E302", "OAuth 토큰 요청에 실패했습니다."),
OAUTH_PROFILE_REQUEST_FAILED(HttpStatus.INTERNAL_SERVER_ERROR, "E303", "OAuth 프로필 요청에 실패했습니다."),
JWT_TOKEN_CREATION_FAILED(HttpStatus.INTERNAL_SERVER_ERROR, "E304", "JWT 토큰 생성에 실패했습니다."),
JWT_TOKEN_EXPIRED(HttpStatus.UNAUTHORIZED, "E305", "JWT 토큰이 만료되었습니다."),
JWT_TOKEN_INVALID(HttpStatus.UNAUTHORIZED, "E306", "유효하지 않은 JWT 토큰입니다."),
REFRESH_TOKEN_NOT_FOUND(HttpStatus.UNAUTHORIZED, "E307", "리프레시 토큰을 찾을 수 없습니다."),
REFRESH_TOKEN_INVALID(HttpStatus.UNAUTHORIZED, "E308", "유효하지 않은 리프레시 토큰입니다."),

// Business Logic Errors (E400~E499)
ENTITY_NOT_FOUND(HttpStatus.NOT_FOUND, "E400", "요청한 데이터를 찾을 수 없습니다."),
DUPLICATE_ENTITY(HttpStatus.CONFLICT, "E401", "중복된 데이터입니다.");

private final HttpStatus status;
USER_NOT_FOUND(HttpStatus.NOT_FOUND, "E401", "사용자를 찾을 수 없습니다."),
DUPLICATE_ENTITY(HttpStatus.CONFLICT, "E402", "중복된 데이터입니다.");

private final HttpStatus httpStatus;
private final String code;
private final String message;
ErrorCode(HttpStatus status, String code, String message) {
this.status = status;

ErrorCode(HttpStatus httpStatus, String code, String message) {
this.httpStatus = httpStatus;
this.code = code;
this.message = message;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.app.oldYoung.global.exception;
package com.app.oldYoung.global.common.apiResponse.exception;

import com.app.oldYoung.global.response.ApiResponse;
import com.app.oldYoung.global.common.apiResponse.response.ApiResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataAccessException;
import org.springframework.http.ResponseEntity;
Expand All @@ -24,7 +24,7 @@ public ResponseEntity<ApiResponse<Void>> handleCustomException(CustomException e
errorCode.getCode(), e.getMessage(), e.getContext());

return ResponseEntity
.status(errorCode.getStatus())
.status(errorCode.getHttpStatus())
.body(ApiResponse.error(errorCode.getCode(), errorCode.getMessage()));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.app.oldYoung.global.response;
package com.app.oldYoung.global.common.apiResponse.response;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.app.oldYoung.global.response;
package com.app.oldYoung.global.common.apiResponse.response;

import lombok.Getter;
import org.springframework.http.HttpStatus;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.app.oldYoung.global.config;
package com.app.oldYoung.global.common.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
Expand Down
Loading