Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
53d9a27
feat: TokenGenerateMachine 삭제
m-a-king Jan 7, 2025
84cd789
feat(auth): userId로 role, accessToken 조회 기능 추가
m-a-king Jan 7, 2025
012215a
feat(auth): 현재 액세스 토큰 기준 userInfo, accessToken 조회 엔드포인트 추가 및 개선
m-a-king Jan 7, 2025
54618b4
feat(token): login 토큰 추가, 구조 개선
m-a-king Jan 7, 2025
9f477f8
feat(user): 유저 정보 dto 정적 팩토리 메서드 추가
m-a-king Jan 7, 2025
f57183b
feat(user): 유저 권한 조회 기능 추가
m-a-king Jan 7, 2025
4f87673
feat(refreshToken): 유저 아이디 기준 리프레시 토큰 조회 기능 추가
m-a-king Jan 7, 2025
ac7222f
feat(refreshToken): 유저 아이디 기준 리프레시 토큰 조회 기능 추가
m-a-king Jan 7, 2025
dc4d972
feat(cookie): 로그인 토큰 설정 기능 추가 및 로직 개선
m-a-king Jan 7, 2025
184d620
feat(cookie): 토큰 타입 파라미터 추가 및 로직 개선
m-a-king Jan 7, 2025
71bb3f9
feat(oauth): 리디렉션 주소 변경 및 로그인 토큰 발급 추가
m-a-king Jan 7, 2025
580fe39
feat(token): 로그인 토큰 생성 기능 추가 및 로직 개선
m-a-king Jan 7, 2025
b33084b
refactor(token): 메서드 네이밍 변경
m-a-king Jan 7, 2025
3aae6c9
refactor(token): 메서드 네이밍 변경
m-a-king Jan 7, 2025
d89bed9
refactor: 병합 충돌 해결
m-a-king Jan 8, 2025
708c5ff
test: 인자 사용
m-a-king Jan 8, 2025
039917b
test(jwt): 사용하지 않는 메서드 삭제
m-a-king Jan 8, 2025
d02e1b7
feat(auth): 메시지 수정
m-a-king Jan 8, 2025
491846b
test(user): 유저 아이디 기준 유저 권한 조회 테스트 추가
m-a-king Jan 8, 2025
fc6c044
refactor(token): 토큰 타입 명명 수정
m-a-king Jan 8, 2025
6cfe14c
refactor: 코드 리뷰 반영
m-a-king Jan 8, 2025
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
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.somemore.global.auth.controller;

import com.somemore.global.auth.annotation.CurrentUser;
import com.somemore.global.auth.dto.UserInfoResponseDto;
import com.somemore.global.auth.jwt.domain.EncodedToken;
import com.somemore.global.auth.usecase.AuthQueryUseCase;
import com.somemore.global.common.response.ApiResponse;
import com.somemore.user.domain.UserRole;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;

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

private final AuthQueryUseCase authQueryUseCase;

@GetMapping("/user-info")
public ApiResponse<UserInfoResponseDto> getUserInfo(
@CurrentUser UUID userId
) {
UserRole role = authQueryUseCase.getRoleByUserId(userId);

return ApiResponse.ok(HttpStatus.OK.value(),
UserInfoResponseDto.of(userId, role),
"유저 정보 응답 성공");
}

@GetMapping("/token")
public ApiResponse<String> getToken(
@CurrentUser UUID userId
) {
EncodedToken accessToken = authQueryUseCase.getAccessTokenByUserId(userId);

return ApiResponse.ok(HttpStatus.OK.value(),
accessToken.getValueWithPrefix(),
"액세스 토큰 응답 성공");
}
}

This file was deleted.

10 changes: 4 additions & 6 deletions src/main/java/com/somemore/global/auth/cookie/CookieService.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,19 @@
public class CookieService implements CookieUseCase {

@Override
public void setAccessToken(HttpServletResponse response, String value) {
ResponseCookie cookie = generateCookie(TokenType.ACCESS, value);
public void setToken(HttpServletResponse response, String value, TokenType tokenType) {
ResponseCookie cookie = generateCookie(tokenType, value);
response.addHeader("Set-Cookie", cookie.toString());
log.info("SET_COOKIE_ACCESS_TOKEN = {}", value);
}

@Override
public void deleteAccessToken(HttpServletResponse response) {
ResponseCookie cookie = generateCookie(TokenType.SIGNOUT, TokenType.SIGNOUT.name());
ResponseCookie cookie = generateCookie(TokenType.SIGN_OUT, TokenType.SIGN_OUT.name());
response.addHeader("Set-Cookie", cookie.toString());
log.info("DELETE_COOKIE_ACCESS_TOKEN");
}

private static ResponseCookie generateCookie(TokenType tokenType, String value) {
return ResponseCookie.from(TokenType.ACCESS.name(), value)
return ResponseCookie.from(TokenType.ACCESS.getDescription(), value)
Copy link
Collaborator

Choose a reason for hiding this comment

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

여기도 from과 of 어떤게 적절할 지 의견나눠보면 좋을거 같아요!

.domain(".somemore.site")
.httpOnly(true)
.secure(true)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.somemore.global.auth.cookie;

import com.somemore.global.auth.jwt.domain.TokenType;
import jakarta.servlet.http.HttpServletResponse;

public interface CookieUseCase {
void setAccessToken(HttpServletResponse response, String value);

void setToken(HttpServletResponse response, String value, TokenType tokenType);

void deleteAccessToken(HttpServletResponse response);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package com.somemore.global.auth.dto;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.somemore.user.domain.UserRole;
import io.swagger.v3.oas.annotations.media.Schema;

import java.util.UUID;

@Schema(description = "유저 정보 DTO")
public record UserInfoResponseDto(
@JsonProperty("USER_ID")
Expand All @@ -13,4 +16,7 @@ public record UserInfoResponseDto(
@Schema(description = "유저 ROLE")
String role
) {
public static UserInfoResponseDto of(UUID userId, UserRole role) {
return new UserInfoResponseDto(userId.toString(), role.getAuthority());
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.somemore.global.auth.idpw.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.somemore.global.auth.cookie.CookieUseCase;
import com.somemore.global.auth.jwt.domain.EncodedToken;
import com.somemore.global.auth.jwt.usecase.GenerateTokensOnLoginUseCase;
import com.somemore.user.domain.UserRole;
Expand Down Expand Up @@ -47,7 +46,7 @@ protected void successfulAuthentication(HttpServletRequest request, HttpServletR
String userId = authResult.getName();
String role = extractRole(authResult);
EncodedToken accessToken =
generateTokensOnLoginUseCase.saveRefreshTokenAndReturnAccessToken(
generateTokensOnLoginUseCase.generateAuthTokensAndReturnAccessToken(
UUID.fromString(userId),
UserRole.from(role));

Expand Down
25 changes: 16 additions & 9 deletions src/main/java/com/somemore/global/auth/jwt/domain/TokenType.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
package com.somemore.global.auth.jwt.domain;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
import java.time.Duration;

@RequiredArgsConstructor
public enum TokenType {
ACCESS(1000 * 60 * 30),
REFRESH(1000 * 60 * 60 * 24 * 7),
SIGNOUT(0);
ACCESS(Duration.ofMinutes(30)),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Duration 기억하겠습니다... 좋네요

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

네 코드가 엄청 깔끔해져서 좋더라구요

REFRESH(Duration.ofDays(7)),
SIGN_IN(Duration.ofMinutes(1)),
SIGN_OUT(Duration.ZERO);

private final Duration period;

private final int period;
public String getDescription() {
return this.name() + "_TOKEN";
}

TokenType(int period) {
this.period = period;
public int getPeriodInMillis() {
return Math.toIntExact(period.toMillis());
}

public int getPeriodInSeconds() {
return Math.toIntExact(period / 1000);
return Math.toIntExact(period.getSeconds());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class HmacJwtGenerator implements JwtGenerator {
public EncodedToken generateToken(String userId, String role, TokenType tokenType) {
Claims claims = buildClaims(userId, role);
Instant now = Instant.now();
Instant expiration = now.plusMillis(tokenType.getPeriod());
Instant expiration = now.plusMillis(tokenType.getPeriodInMillis());
String uniqueId = UUID.randomUUID().toString(); // JTI

return new EncodedToken(Jwts.builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,26 @@
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.UUID;

@Service
@RequiredArgsConstructor
public class RedisRefreshTokenManager implements RefreshTokenManager {

private final RefreshTokenRepository refreshTokenRepository;

@Override
public RefreshToken findRefreshToken(EncodedToken accessToken) {
public RefreshToken findRefreshTokenByAccessToken(EncodedToken accessToken) {
return refreshTokenRepository.findByAccessToken(accessToken.value())
.orElseThrow(() -> new JwtException(JwtErrorType.EXPIRED_TOKEN));
}

@Override
public RefreshToken findRefreshTokenByUserId(UUID userId) {
return refreshTokenRepository.findByUserId(userId.toString())
.orElseThrow(() -> new JwtException(JwtErrorType.EXPIRED_TOKEN));
}

@Override
public void save(RefreshToken refreshToken) {
refreshTokenRepository.save(refreshToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@
import com.somemore.global.auth.jwt.domain.EncodedToken;
import com.somemore.global.auth.jwt.refresh.domain.RefreshToken;

import java.util.UUID;

public interface RefreshTokenManager {
RefreshToken findRefreshToken(EncodedToken accessToken);
RefreshToken findRefreshTokenByAccessToken(EncodedToken accessToken);

RefreshToken findRefreshTokenByUserId(UUID userId);

void save(RefreshToken refreshToken);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class DefaultJwtRefresher implements JwtRefresher {

@Override
public EncodedToken refreshAccessToken(EncodedToken accessToken) {
RefreshToken refreshToken = refreshTokenManager.findRefreshToken(accessToken);
RefreshToken refreshToken = refreshTokenManager.findRefreshTokenByAccessToken(accessToken);
EncodedToken refreshTokenValue = new EncodedToken(refreshToken.getRefreshToken());
jwtValidator.validateToken(refreshTokenValue);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,32 @@ public class GenerateTokensOnLoginService implements GenerateTokensOnLoginUseCas
private final RefreshTokenManager refreshTokenManager;

@Override
public EncodedToken saveRefreshTokenAndReturnAccessToken(UUID userId, UserRole role) {
EncodedToken accessToken = jwtGenerator.generateToken(
userId.toString(),
role.getAuthority(),
TokenType.ACCESS
);
RefreshToken refreshToken = generateRefreshToken(userId, role, accessToken);
public EncodedToken generateLoginToken(UUID userId, UserRole role) {
return generateToken(userId, role, TokenType.SIGN_IN);
}

@Override
public EncodedToken generateAuthTokensAndReturnAccessToken(UUID userId, UserRole role) {
EncodedToken accessToken = generateToken(userId, role, TokenType.ACCESS);
RefreshToken refreshToken = generateRefreshTokenWithAccessToken(userId, role, accessToken);
saveRefreshToken(refreshToken);

return accessToken;
}

private RefreshToken generateRefreshToken(UUID userId, UserRole role, EncodedToken accessToken) {
private EncodedToken generateToken(UUID userId, UserRole role, TokenType tokenType) {
return jwtGenerator.generateToken(
userId.toString(),
role.getAuthority(),
tokenType
);
}

private RefreshToken generateRefreshTokenWithAccessToken(UUID userId, UserRole role, EncodedToken accessToken) {
return new RefreshToken(
userId.toString(),
accessToken,
jwtGenerator.generateToken(
userId.toString(),
role.getAuthority(),
TokenType.REFRESH)
generateToken(userId, role, TokenType.REFRESH)
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public Claims getClaims(EncodedToken token) {
private void handleJwtExpiredException(JwtException e, EncodedToken accessToken, HttpServletResponse response) {
if (e.getErrorType() == JwtErrorType.EXPIRED_TOKEN) {
EncodedToken refreshedToken = jwtRefresher.refreshAccessToken(accessToken);
cookieUseCase.setAccessToken(response, refreshedToken.value());
cookieUseCase.setToken(response, refreshedToken.value(), TokenType.ACCESS);
return;
}
throw e;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
import java.util.UUID;

public interface GenerateTokensOnLoginUseCase {
EncodedToken saveRefreshTokenAndReturnAccessToken(UUID userId, UserRole role);
EncodedToken generateLoginToken(UUID userId, UserRole role);
EncodedToken generateAuthTokensAndReturnAccessToken(UUID userId, UserRole role);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.somemore.global.auth.oauth.handler;

import com.somemore.global.auth.cookie.CookieUseCase;
import com.somemore.global.auth.jwt.domain.EncodedToken;
import com.somemore.global.auth.jwt.domain.TokenType;
import com.somemore.global.auth.jwt.usecase.GenerateTokensOnLoginUseCase;
import com.somemore.global.auth.oauth.processor.OAuthUserProcessor;
import com.somemore.global.auth.redirect.RedirectUseCase;
Expand All @@ -24,10 +26,10 @@ public class CustomOAuthSuccessHandler extends SimpleUrlAuthenticationSuccessHan

private final OAuthUserProcessor oauthUserProcessor;
private final GenerateTokensOnLoginUseCase generateTokensOnLoginUseCase;
private final CookieUseCase cookieUseCase;
private final RedirectUseCase redirectUseCase;

public static final String AUTHORIZATION = "Authorization";
public static final String MAIN_PATH = "/main";
public static final String SUCCESS_PATH = "/success";

@Override
public void onAuthenticationSuccess(HttpServletRequest request,
Expand All @@ -42,15 +44,18 @@ public void onAuthenticationSuccess(HttpServletRequest request,

private void redirect(HttpServletRequest request, HttpServletResponse response) {
// TODO 유저 정보 커스텀 확인 분기
redirectUseCase.redirect(request, response, MAIN_PATH);
redirectUseCase.redirect(request, response, SUCCESS_PATH);
}

private void processAccessToken(HttpServletResponse response, UUID userId) {
EncodedToken accessToken =
generateTokensOnLoginUseCase.saveRefreshTokenAndReturnAccessToken(
generateTokensOnLoginUseCase.generateAuthTokensAndReturnAccessToken(
userId, UserRole.getOAuthUserDefaultRole());

EncodedToken loginToken =
generateTokensOnLoginUseCase.generateLoginToken(
userId, UserRole.getOAuthUserDefaultRole());

response.addHeader(AUTHORIZATION, accessToken.getValueWithPrefix());
cookieUseCase.setToken(response, loginToken.getValueWithPrefix(), TokenType.SIGN_IN);
}

private OAuth2User extractOAuthUser(Authentication authentication) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.somemore.global.auth.usecase;

import com.somemore.global.auth.jwt.domain.EncodedToken;
import com.somemore.global.auth.jwt.refresh.manager.RefreshTokenManager;
import com.somemore.user.domain.UserRole;
import com.somemore.user.usecase.UserQueryUseCase;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.UUID;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class AuthQueryService implements AuthQueryUseCase {

private final UserQueryUseCase userQueryUseCase;
private final RefreshTokenManager refreshTokenManager;

@Override
public UserRole getRoleByUserId(UUID userId) {
return userQueryUseCase.getRoleById(userId);
}

@Override
public EncodedToken getAccessTokenByUserId(UUID userId) {
return new EncodedToken(
refreshTokenManager.findRefreshTokenByUserId(userId)
.getAccessToken());
}
}
Loading
Loading