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 @@ -48,6 +48,18 @@ public ApiResponse<AuthResponseDto.LoginResponse> socialLogin(
return ApiResponse.of(AuthSuccessStatus.SOCIAL_LOGIN_SUCCESS, response);
}

@Operation(
summary = "게스트 로그인",
description = "UUID 기반 게스트 계정을 생성하고 엑세스/리프레시 토큰을 발급합니다."
)
@PostMapping(value = "/guest-login", produces = "application/json")
public ApiResponse<AuthResponseDto.LoginResponse> guestLogin(
) {
AuthResponseDto.LoginResponse response = authService.guestLogin();
return ApiResponse.of(AuthSuccessStatus.GUEST_LOGIN_SUCCESS, response);
}


@Operation(
summary = "엑세스 토큰 재발급",
description = "리프레시 토큰을 이용해 엑세스 토큰을 재발급합니다."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ public enum AuthSuccessStatus implements BaseCode {
SOCIAL_LOGIN_SUCCESS(HttpStatus.OK, "AUTH2001", "소셜 로그인이 완료되었습니다."),
DEV_TOKEN_ISSUED(HttpStatus.OK, "AUTH2002", "개발용 액세스 토큰 발급이 완료되었습니다."),
LOGOUT_SUCCESS(HttpStatus.OK, "AUTH2003", "로그아웃이 완료되었습니다."),
AT_REFRESH_SUCCESS(HttpStatus.OK, "AUTH2004", "엑세스 토큰 재생성이 완료되었습니다.");
AT_REFRESH_SUCCESS(HttpStatus.OK, "AUTH2004", "엑세스 토큰 재생성이 완료되었습니다."),
GUEST_LOGIN_SUCCESS(HttpStatus.OK, "AUTH2005", "게스트 로그인이 완료되었습니다."),

;

private final HttpStatus httpStatus;
private final String code;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.perfact.be.domain.auth.service;

import com.perfact.be.domain.auth.dto.AuthResponseDto;
import com.perfact.be.domain.auth.dto.AuthResponseDto.LoginResponse;
import com.perfact.be.domain.auth.dto.AuthResponseDto.TokenResponse;
import com.perfact.be.domain.user.entity.User;
import jakarta.validation.constraints.NotNull;
Expand All @@ -12,4 +13,6 @@ public interface AuthService {
TokenResponse refreshAccessToken(User loginUser, String refreshToken);

void logout(User loginUser, String refreshToken);

AuthResponseDto.LoginResponse guestLogin();
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.perfact.be.domain.auth.service;

import com.perfact.be.domain.auth.dto.AuthResponseDto;
import com.perfact.be.domain.auth.dto.AuthResponseDto.LoginResponse;
import com.perfact.be.domain.auth.dto.AuthResponseDto.TokenResponse;
import com.perfact.be.domain.auth.dto.NaverTokenResponse;
import com.perfact.be.domain.auth.dto.NaverUserInfoResponse;
Expand Down Expand Up @@ -85,6 +86,21 @@ public void logout(User loginUser, String refreshToken) {
redisTemplate.delete(redisKey);
}

@Override
public LoginResponse guestLogin() {
Copy link
Member

Choose a reason for hiding this comment

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

UUID 기반 디바이스 식별자 사용하시는 방안 확인했습니다!
deviceUuid와 rtUuid 분리해서 생성하시는 것도 고생많으셨어용

String deviceUuid = UUID.randomUUID().toString();
User guestUser = userService.createGuestUser(deviceUuid);

String accessToken = jwtProvider.generateAccessToken(guestUser.getId(), deviceUuid);

String rtUuid = UUID.randomUUID().toString();
String refreshToken = jwtProvider.generateRefreshToken(guestUser.getId(), deviceUuid, rtUuid);

String redisKey = "RT:" + deviceUuid + ":" + rtUuid;
redisTemplate.opsForValue().set(redisKey, refreshToken, 3, TimeUnit.HOURS);
return new AuthResponseDto.LoginResponse(guestUser.getId(), guestUser.getEmail(), accessToken, refreshToken);
}


private String getAccessToken(String code, String state) {
NaverTokenResponse tokenResponse = webClient
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package com.perfact.be.domain.credit.entity.enums;

public enum PlanType {
FREE, STANDARD, PREMIUM
FREE, STANDARD, PREMIUM, GUEST
}
3 changes: 1 addition & 2 deletions src/main/java/com/perfact/be/domain/user/entity/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,14 @@ public class User extends BaseEntity {
private String socialId;
@Enumerated(EnumType.STRING)
private SocialType socialType;
@Column(name = "nickname", length = 10)
@Column(name = "nickname", length = 20)
private String nickname;
@Column(name = "email", length = 255)
private String email;
@Enumerated(EnumType.STRING)
@Column(length = 20)
private Role role;
@Enumerated(EnumType.STRING)

@Builder.Default
@Column(length = 20, nullable = false)
private UserStatus status = UserStatus.ACTIVE;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package com.perfact.be.domain.user.entity.enums;

public enum Role {
ROLE_USER, ROLE_ADMIN
ROLE_USER, ROLE_ADMIN, ROLE_GUEST;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package com.perfact.be.domain.user.entity.enums;

public enum SocialType {
NAVER, KAKAO
NAVER, KAKAO, GUEST
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@ public interface UserService {
void decreaseCredit(User user, int cost);

NicknameResponse getNickname(User loginUser);

User createGuestUser(String deviceUuid);
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,23 @@ public SubscribeStatusResponse getSubscribeStatus(User loginUser) {

String planName = plan != null ? plan.getName().toString() : "UNKNOWN";
boolean isFreePlan = "FREE".equals(planName);
String subscribeStatus = isFreePlan ? "무료 플랜 사용 중" : "유료 플랜 사용 중";
String nextBillingDate = isFreePlan ? "무료 플랜 사용 중" : "미정";
boolean isGuestPlan = "GUEST".equals(planName);

String subscribeStatus;
String nextBillingDate;
Long dailyCredit = plan != null ? plan.getDailyCredit() : 0L;

if (isGuestPlan) {
subscribeStatus = "게스트 모드 사용 중";
nextBillingDate = "게스트 모드는 결제/갱신 없음";
} else if (isFreePlan) {
subscribeStatus = "무료 플랜 사용 중";
nextBillingDate = "무료 플랜 사용 중";
} else {
subscribeStatus = "유료 플랜 사용 중";
nextBillingDate = "미정"; // TODO : 유료 결제 로직 붙으면 수정
}

LocalDateTime startOfToday = LocalDate.now().atStartOfDay();
LocalDateTime startOfTomorrow = startOfToday.plusDays(1);

Expand All @@ -70,35 +83,64 @@ public SubscribeStatusResponse getSubscribeStatus(User loginUser) {

// 오늘 사용량
Long todayUsage = Optional.ofNullable(
creditLogRepository.sumUsedCreditByUserAndTypeAndCreatedAtBetween(
loginUser,
CreditLogType.REPORT_CREATE,
startOfToday,
startOfTomorrow))
creditLogRepository.sumUsedCreditByUserAndTypeAndCreatedAtBetween(
loginUser,
CreditLogType.REPORT_CREATE,
startOfToday,
startOfTomorrow))
.map(Math::abs).orElse(0L);

// 이번 달 사용량
Long thisMonthUsage = Optional.ofNullable(
creditLogRepository.sumUsedCreditByUserAndTypeAndCreatedAtBetween(
loginUser,
CreditLogType.REPORT_CREATE,
startOfMonth,
startOfNextMonth))
creditLogRepository.sumUsedCreditByUserAndTypeAndCreatedAtBetween(
loginUser,
CreditLogType.REPORT_CREATE,
startOfMonth,
startOfNextMonth))
.map(Math::abs).orElse(0L);
return new SubscribeStatusResponse(
planName,
subscribeStatus,
nextBillingDate,
dailyCredit,
todayUsage,
thisMonthUsage);
thisMonthUsage
);
}

@Override
public NicknameResponse getNickname(User loginUser) {
return new NicknameResponse(loginUser.getNickname());
}

@Override
@Transactional
public User createGuestUser(String deviceUuid) {
return userRepository.findBySocialIdAndSocialType(deviceUuid, SocialType.GUEST)
.orElseGet(() -> {
// 테스트로 지정하기
SubscriptionPlans testPlan = subscriptionPlansRepository.findByName(PlanType.GUEST)
.orElseThrow(() -> new UserHandler(UserErrorStatus.PLAN_NOT_FOUND));

String nick = "게스트-" + deviceUuid.substring(0, 8);

User newGuest = User.builder()
.email(null) // 게스트는 이메일 없음.. 기획 보고 나중에 수정해야 될 수도 있음.
.nickname(nick)
.socialId(deviceUuid)
.socialType(SocialType.GUEST)
.role(Role.ROLE_GUEST)
.status(UserStatus.ACTIVE)
.plan(testPlan)
.isSubscribe(false)
.isNotificationAgreed(false)
.build();

return userRepository.save(newGuest);
});
}


@Override
@Transactional
public void decreaseCredit(User user, int amount) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
"/v3/api-docs/**",
"/swagger-ui.html",
"/api/auth/social-login/**",
"/api/auth/guest-login/**",
"/dev/auth/**"
).permitAll()
.anyRequest().authenticated()
Expand Down