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 @@ -23,7 +23,7 @@ public interface AuthControllerDocs {
사용자가 앱을 처음 설치하고 실행했을 때 호출되는 API입니다.

- **기능**: 기기 고유 ID(UUID)를 등록하고, **초기 토큰 3종(Access, Refresh, Recover)**을 발급합니다.
- **주의**:
- **주의**:
1. 이미 등록된 기기라면 에러가 발생합니다. (로그인 API 사용 권장)
2. 등록된 기기임을 클라이언트에서 확인할 때, recoverToken의 여부를 확인하세요. (recoverToken이 없다면 처음 로그인 한 것임)
""")
Expand Down Expand Up @@ -105,11 +105,11 @@ public interface AuthControllerDocs {
@Operation(summary = "Google 회원가입 (소셜 계정 연동)", description = """
안드로이드 앱에서 Google 로그인을 수행한 후, 발급받은 **ID Token**을 전송하여 회원가입을 수행합니다.

- **기능**:
- **기능**:
1. Google ID Token의 서명 및 Audience(Client ID)를 검증합니다.
2. 검증된 정보로 신규 가입을 진행하고 **Access, Refresh Token**을 발급합니다.

- **주의사항**:
- **주의사항**:
1. **Google 로그인은 Recover Token을 발급하지 않습니다.** (Response의 recoverToken 값은 null입니다.)
- 이유: 계정 복구 및 신원 증명은 Google이 담당하기 때문입니다.
2. 이미 가입된 Google 계정이라면 409 Conflict 에러가 발생합니다.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
public record JwtTokenResDto(
String accessToken,
String refreshToken,
String recoverToken // 회원가입 시에만 값 존재하며, 로그인 시에는 null
String recoverToken, // 회원가입 시에만 값 존재하며, 로그인 시에는 null
String email
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
import com.example.egobook_be.global.security.CustomUserDetails;
import com.example.egobook_be.global.util.module.RedisValue;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
Expand Down Expand Up @@ -81,8 +80,6 @@ public class AuthService {
* **주의사항**
* 1. Google 계정은 Recover Token을 발급하지 않는다.
* 2. Google Sub값을 해싱하여, AuthAccount Table의 HashedDeviceUid 컬럼에 저장한다.
* @param reqDto
* @return
*/
@Transactional
public JwtTokenResDto registerGoogle(GoogleJoinReqDto reqDto){
Expand Down Expand Up @@ -139,7 +136,7 @@ public JwtTokenResDto registerGoogle(GoogleJoinReqDto reqDto){
* 8. 클라이언트에게 토큰 반환
* - Google 로그인이므로 recoverToken은 null을 반환한다.
*/
return buildJwtTokenResDto(accessTokenInfo.token(), refreshTokenInfo.token(), null);
return buildJwtTokenResDto(accessTokenInfo.token(), refreshTokenInfo.token(), null, email);
}


Expand Down Expand Up @@ -202,7 +199,7 @@ public JwtTokenResDto registerGuest(GuestJoinReqDto reqDto){
* 10. 클라이언트에게 토큰을 반환
* recoverToken은 회원가입, refreshToken 재발급 시에만 발급된다.
*/
return buildJwtTokenResDto(accessTokenInfo.token(), refreshTokenInfo.token(), recoverTokenInfo.token());
return buildJwtTokenResDto(accessTokenInfo.token(), refreshTokenInfo.token(), recoverTokenInfo.token(), null);
}


Expand Down Expand Up @@ -230,7 +227,7 @@ public JwtTokenResDto refreshToken(RefreshReqDto reqDto){
// 기존 AccessToken Redis 블랙리스트에 추가
addAccessTokenInRedisBlackList(reqDto.accessToken());
TokenInfo newAccessTokenInfo = jwtUtil.createAccessToken(redisValue.userId(), redisValue.authAccountId(), redisValue.subject(), redisValue.role());
return buildJwtTokenResDto(newAccessTokenInfo.token(), reqDto.refreshToken(), null);
return buildJwtTokenResDto(newAccessTokenInfo.token(), reqDto.refreshToken(), null, null);
}

/*
Expand Down Expand Up @@ -275,7 +272,7 @@ public JwtTokenResDto refreshToken(RefreshReqDto reqDto){

// 7. Access Token 재생성 후 Access, Refresh Token 반환
TokenInfo newAccessTokenInfo = jwtUtil.createAccessToken(user.getId(), authAccount.getId(), subject, user.getRole());
return buildJwtTokenResDto(newAccessTokenInfo.token(), reqDto.refreshToken(), null);
return buildJwtTokenResDto(newAccessTokenInfo.token(), reqDto.refreshToken(), null, null);
}

/** HttpServletRequest에 들어있는 AccessToken 추출 및 블랙리스트 등록 */
Expand Down Expand Up @@ -371,7 +368,7 @@ public JwtTokenResDto recertificationGuestToken(GuestRecertificationReqDto reqDt
registerToRedis(newHashedRefreshToken, newRedisValue, newRefreshTokenInfo.expiresAt());

// 9. 결과 반환
return buildJwtTokenResDto(newAccessTokenInfo.token(), newRefreshTokenInfo.token(), newRecoverTokenInfo.token());
return buildJwtTokenResDto(newAccessTokenInfo.token(), newRefreshTokenInfo.token(), newRecoverTokenInfo.token(), null);
}

/**
Expand Down Expand Up @@ -421,7 +418,7 @@ public JwtTokenResDto recertificationGoogleToken(GoogleRecertificationReqDto req
processRefreshTokenSaving(user, authAccount, refreshTokenInfo);

// 6. 반환
return buildJwtTokenResDto(accessTokenInfo.token(), refreshTokenInfo.token(), null);
return buildJwtTokenResDto(accessTokenInfo.token(), refreshTokenInfo.token(), null, user.getEmail());
}

/**
Expand Down Expand Up @@ -489,7 +486,7 @@ public JwtTokenResDto linkGoogleAccount(Long userId, GoogleJoinReqDto reqDto) {
processRefreshTokenSaving(user, googleAuthAccount, refreshTokenInfo);

// 9. 반환 (Google이므로 Recover Token은 비워놓고 반환한다)
return buildJwtTokenResDto(accessTokenInfo.token(), refreshTokenInfo.token(), null);
return buildJwtTokenResDto(accessTokenInfo.token(), refreshTokenInfo.token(), null, user.getEmail());
}


Expand All @@ -503,7 +500,6 @@ public JwtTokenResDto linkGoogleAccount(Long userId, GoogleJoinReqDto reqDto) {
* - email은 선택적으로 넣을 수 있다.
* - User 생성 후, userRepository에 save()까지 수행한 결과물을 반환한다.
* @param email : Guest-null, Google-Token에 있는 Google Email 설정
* @return
*/
private User createUser(String email){
/*
Expand Down Expand Up @@ -540,7 +536,6 @@ private User createUser(String email){
* @param user 연동할 user
* @param provider 해당 회원가입 주체
* @param hashedDeviceUid Guest->hashedDeviceUid, Google->hashedGoogleId
* @return
*/
private AuthAccount createAuthAccount(User user, Provider provider, String hashedDeviceUid){
AuthAccount authAccount = AuthAccount.builder()
Expand All @@ -559,7 +554,6 @@ private AuthAccount createAuthAccount(User user, Provider provider, String hashe
* (1) authAccount.deviceUid -> refreshTokenBackup.deviceUid (authAccount 테이블이 deviceUid를 관리하는 책임자이다.)
* (2) TokenInfo.token -> refreshTokenBackup.tokenValue
* (3) TokenInfo.expiresAt -> refreshTokenBackup.expiresAt
*
* [ 신규 추가 로직 ]
* (1) RefreshTokenBackup 새로 생성하여 authAccount.updateRefreshTokenBackup(...)으로 연결
* -> 영속성 컨텍스트의 Dirty Checking으로 트랜잭션 종료 시 Update됨
Expand Down Expand Up @@ -594,9 +588,6 @@ private void updateRefreshTokenBackupTable(AuthAccount authAccount, String hashe

/**
* key, value, expiresAt(절대시간)을 입력받아 redis에 등록해주는 함수
* @param key
* @param value
* @param expiresAt
*/
private void registerToRedis(String key, RedisValue value, LocalDateTime expiresAt){
long ttlInMillis = getDurationInMillis(expiresAt); // 현재 ~ refreshToken의 만료시간까지 남은 밀리초 계산
Expand All @@ -611,21 +602,20 @@ private void registerToRedis(String key, RedisValue value, LocalDateTime expires
/**
* LocalDateTime (절대시간)까지 남은 시간을 millis로 반환해주는 함수
* @param at : 목표 절대 시간
* @return
*/
private long getDurationInMillis(LocalDateTime at){
return Duration.between(LocalDateTime.now(), at).toMillis(); // 밀리초로 변환
}

/**
* JwtTokenResDto를 빌드하는 함수
* @return
*/
private JwtTokenResDto buildJwtTokenResDto(String accessToken, String refreshToken, String recoverToken){
private JwtTokenResDto buildJwtTokenResDto(String accessToken, String refreshToken, String recoverToken, String email){
return JwtTokenResDto.builder()
.accessToken(accessToken)
.refreshToken(refreshToken)
.recoverToken(recoverToken)
.email(email)
.build();
}

Expand Down Expand Up @@ -676,9 +666,6 @@ private CustomUserDetails buildCustomUserDetails(User user, AuthAccount authAcco

/**
* 모든 토큰들을 발급한 뒤, Refresh Token을 Table, Redis에 저장하는 Process를 수행해주는 함수
* @param user
* @param authAccount
* @param refreshTokenInfo
*/
private void processRefreshTokenSaving(User user, AuthAccount authAccount, TokenInfo refreshTokenInfo){
// 1. Refresh Token을 RefreshTokenBackup Table에 추가(Update)
Expand All @@ -705,7 +692,6 @@ private void processRefreshTokenSaving(User user, AuthAccount authAccount, Token
* (1) 기본 UserItem 인스턴스 생성
* (2) 기본 Ability 인스턴스 생성
* (3) UserTerm 인스턴스 생성
* @param user
*/
private void allocateUser(User user){
// 1. 사용자 UserItems 생성
Expand Down Expand Up @@ -747,7 +733,6 @@ private List<UserItem> createDefaultUserItems(User user){
/**
* user 생성 시 ability 생성 로직 (능력치)
* @param user 연동할 user
* @return
*/
private Ability createDefaultAbility(User user) {
Ability ability = Ability.builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,10 @@ ResponseEntity<GlobalResponse<HomeAbilityResDto>> getHomeAbilities(

@Operation(summary = "사용자 설정/계정 페이지 정보 조회", description = """
홈 화면의 '설정(계정)' 탭에 필요한 데이터를 조회합니다.
현재는 사용자 계정 ID(Account Code)를 반환합니다.

[ 반환 데이터 ]
1. 사용자 계정 ID(Account Code)
2. 사용자 이메일 (Google 연동 했을 시에만 반환됩니다)
""")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "조회 성공", content = @Content(schema = @Schema(implementation = HomeSettingResDto.class)))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package com.example.egobook_be.domain.home.dto;

import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;

@Builder
public record HomeSettingResDto(
@Schema(description = "사용자 고유 계정 ID (Account Code)", example = "EGO-123456")
String accountCode
String accountCode,
@Schema(description = "사용자 Email", example = "example@google.com")
@JsonInclude(JsonInclude.Include.NON_NULL)
String userEmail
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ private HomeAbilityResDto.AbilityInfo toAbilityInfo(AbilityStat abilityStat) {

public HomeSettingResDto toHomeSettingResDto(User user) {
return HomeSettingResDto.builder()
.userEmail(user.getEmail())
.accountCode(user.getAccountCode())
.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@ public class Term extends BaseTimeEntity {
@Builder.Default
private TermVersion termVersion = TermVersion.V1;

// 대용량 텍스트 저장을 위해 Lob 사용
@Lob
@Column(name = "context", nullable = false, columnDefinition = "LONGTEXT")
@Column(name = "context", nullable = false)
private String context;

@Column(name = "required", nullable = false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,14 @@ public enum TermTemplate {
TERM_OF_SERVICE(
TermType.TERM_OF_SERVICE,
"서비스 이용 약관",
"""
서비스 이용 약관 임시 내용
""",
"https://bevel-beetle-a49.notion.site/2f638a539ac5801aa872e99ec4282f28?source=copy_link",
true
),
TERM_OF_PRIVACY_POLICY(
TermType.TERM_OF_PRIVACY_POLICY,
"개인정보 처리 방침",
"""
개인정보 처리 방침 임시 내용
""",
"개인정보 수집 및 이용",
"https://bevel-beetle-a49.notion.site/2f638a539ac58059b9a1c883ad7d7164?source=copy_link",
true
),
TERM_OF_PERSONAL_INFO_CONSENT(
TermType.TERM_OF_PERSONAL_INFO_CONSENT,
"개인정보 이용 동의 약관",
"""
개인정보 이용 동의 약관 임시 내용
""",
false
);

private final TermType termType;
Expand Down
Loading