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
@@ -1,10 +1,8 @@
package com.jobnote.auth.handler;

import com.jobnote.auth.dto.CustomUserDetails;
import com.jobnote.auth.token.Token;
import com.jobnote.auth.token.TokenProvider;
import com.jobnote.domain.user.domain.UserRole;
import com.jobnote.domain.user.service.AuthTokenService;
import com.jobnote.domain.code.service.TempCodeService;
import com.jobnote.global.config.properties.FrontendProperties;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
Expand All @@ -21,8 +19,7 @@
@Component
public class OAuth2LoginSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

private final TokenProvider tokenProvider;
private final AuthTokenService authTokenService;
private final TempCodeService tempCodeService;
private final FrontendProperties frontendProperties;

@Override
Expand All @@ -34,10 +31,8 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo
return;
}

final Token token = authTokenService.saveAndGetToken(principal.getUserId());
tokenProvider.responseToken(response, token);

response.sendRedirect(memberRedirectUrl());
final String code = tempCodeService.create(principal.getUserId());
response.sendRedirect(memberRedirectUrl(code));
}

private String guestRedirectUrl(final String email) {
Expand All @@ -49,7 +44,11 @@ private String guestRedirectUrl(final String email) {
.toUriString();
}

private String memberRedirectUrl() {
return frontendProperties.baseUrl() + frontendProperties.mainPage();
private String memberRedirectUrl(final String code) {
return UriComponentsBuilder.fromUriString(frontendProperties.baseUrl())
.path(frontendProperties.mainPage())
.queryParam("code", code)
.build()
.toUriString();
}
}
44 changes: 44 additions & 0 deletions src/main/java/com/jobnote/domain/code/domain/TempCode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.jobnote.domain.code.domain;

import com.jobnote.global.exception.JobNoteException;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.*;

import java.time.LocalDateTime;

import static com.jobnote.global.common.ResponseCode.EXPIRED_TEMP_CODE;

@Entity
@Getter
@Table(name = "temp_codes")
@Builder(access = AccessLevel.PACKAGE)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class TempCode {

@Id
private String code;

@Column(nullable = false)
private long userId;

@Column(nullable = false)
private LocalDateTime expireAt;

public static TempCode of(final String code, final long userId, final LocalDateTime expireAt) {
return TempCode.builder()
.code(code)
.userId(userId)
.expireAt(expireAt)
.build();
}

public void validateExpiration(final LocalDateTime now) {
if (expireAt.isBefore(now)) {
throw new JobNoteException(EXPIRED_TEMP_CODE);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.jobnote.domain.code.repository;

import com.jobnote.domain.code.domain.TempCode;
import org.springframework.data.jpa.repository.JpaRepository;

public interface TempCodeRepository extends JpaRepository<TempCode, String> {
}
42 changes: 42 additions & 0 deletions src/main/java/com/jobnote/domain/code/service/TempCodeService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.jobnote.domain.code.service;

import com.jobnote.domain.code.domain.TempCode;
import com.jobnote.domain.code.repository.TempCodeRepository;
import com.jobnote.domain.common.Time;
import com.jobnote.global.exception.JobNoteException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.UUID;

import static com.jobnote.global.common.ResponseCode.*;

@RequiredArgsConstructor
@Transactional(readOnly = true)
@Service
public class TempCodeService {

private final TempCodeRepository tempCodeRepository;
private final Time time;

@Transactional
public String create(final long userId) {
final String code = UUID.randomUUID().toString();
tempCodeRepository.save(TempCode.of(code, userId, time.now().plusMinutes(1)));

return code;
}

@Transactional
public long validate(final String code) {
final TempCode tempCode = tempCodeRepository.findById(code)
.orElseThrow(() -> new JobNoteException(NOT_FOUND_TEMP_CODE));

tempCode.validateExpiration(time.now());

tempCodeRepository.delete(tempCode);

return tempCode.getUserId();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,14 @@ public ResponseEntity<ApiResponse<Void>> logout(final HttpServletRequest request
return ResponseEntity.ok(ApiResponse.ofSuccess(ResponseCode.OK));
}

/* TOKEN REISSUE */
/* TOKEN ISSUE */
@PostMapping("/issue/code")
public ResponseEntity<ApiResponse<Void>> tokenIssueByCode(@RequestBody @Valid final TokenIssueRequest request, final HttpServletResponse response) {
final Token token = authTokenService.issueByCode(request.code());
tokenProvider.responseToken(response, token);
return ResponseEntity.ok(ApiResponse.ofSuccess(ResponseCode.OK));
}

@PostMapping("/reissue")
public ResponseEntity<ApiResponse<Void>> tokenReissue(final HttpServletRequest request, final HttpServletResponse response) {
final Token token = authTokenService.reissue(getValueFromCookie(request.getCookies(), COOKIE_NAME_REFRESH_TOKEN));
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/com/jobnote/domain/user/dto/TokenIssueRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.jobnote.domain.user.dto;

import jakarta.validation.constraints.NotEmpty;

public record TokenIssueRequest(

@NotEmpty(message = "코드는 비어 있을 수 없습니다.")
String code
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.jobnote.auth.token.Token;
import com.jobnote.auth.token.TokenClaim;
import com.jobnote.auth.token.TokenProvider;
import com.jobnote.domain.code.service.TempCodeService;
import com.jobnote.domain.refreshtoken.domain.RefreshToken;
import com.jobnote.domain.user.domain.User;
import com.jobnote.domain.refreshtoken.repository.RefreshTokenRepository;
Expand All @@ -24,6 +25,7 @@ public class AuthTokenService {
private final TokenProvider tokenProvider;
private final RefreshTokenRepository refreshTokenRepository;
private final UserQueryService userQueryService;
private final TempCodeService tempCodeService;

@Transactional
public Token saveAndGetToken(final Long userId) {
Expand All @@ -45,6 +47,12 @@ public Token reissue(final String existingRefreshToken) {
return saveAndGetToken(refreshToken.getUser().getId());
}

@Transactional
public Token issueByCode(final String code) {
final long userId = tempCodeService.validate(code);
return saveAndGetToken(userId);
}

@Transactional
public void invalidate(final String targetRefreshToken) {
validateExistsRefreshToken(targetRefreshToken);
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/jobnote/global/common/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public abstract class Constants {
public static final String[] WHITELIST = {
"/api/v1/users/signup/**",
"/api/v1/users/login",
"/api/v1/users/issue/code",
"/api/v1/users/reissue",
"/api/v1/users/reset-password",
"/api/v1/verification-emails/**",
Expand All @@ -39,6 +40,7 @@ public abstract class Constants {
"/api/v1/users/signup",
"/api/v1/users/signup/social",
"/api/v1/users/login",
"/api/v1/users/issue/code",
"/api/v1/users/reissue",
"/api/v1/users/reset-password",
"/api/v1/verification-emails",
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/jobnote/global/common/ResponseCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public enum ResponseCode {
VERIFICATION_EMAIL_ALREADY_VERIFIED(HttpStatus.BAD_REQUEST, "4005", "이미 인증이 완료된 인증 이메일입니다."),
INVALID_HEADER(HttpStatus.BAD_REQUEST, "4006", "헤더가 올바르지 않습니다."),
INVALID_COOKIE(HttpStatus.BAD_REQUEST, "4007", "쿠키가 올바르지 않습니다."),
EXPIRED_TEMP_CODE(HttpStatus.BAD_REQUEST, "4008", "만료된 임시 코드입니다."),

// 401 Unauthorized
UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "4010", "요청 리소스에 대한 액세스 권한이 없습니다."),
Expand Down Expand Up @@ -49,6 +50,7 @@ public enum ResponseCode {
NOT_FOUND_REFRESH_TOKEN(HttpStatus.NOT_FOUND, "4045", "해당 리프레시 토큰을 찾을 수 없습니다."),
NOT_FOUND_DOCUMENT(HttpStatus.NOT_FOUND, "4046", "해당 문서를 찾을 수 없습니다."),
NOT_FOUND_S3_FILE(HttpStatus.NOT_FOUND, "4047", "업로드된 문서가 아닙니다."),
NOT_FOUND_TEMP_CODE(HttpStatus.NOT_FOUND, "4048", "임시 코드를 찾을 수 없습니다."),

// 405 Method Not Allowed
METHOD_NOT_ALLOWED(HttpStatus.METHOD_NOT_ALLOWED, "4050", "요청 메소드를 지원하지 않습니다."),
Expand Down
Loading