-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feature/#64 rtr 기반 refresh token 발행 기능 구현 #65
Changes from 6 commits
10ce949
c3891d0
61c7d32
3d47742
19e485b
317d96f
5402b76
909ba79
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package sorisoop.soridam.api.auth.application; | ||
|
||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import sorisoop.soridam.api.auth.presentation.request.jwt.JwtLoginRequest; | ||
import sorisoop.soridam.api.auth.presentation.request.jwt.RefreshTokenRequest; | ||
import sorisoop.soridam.api.auth.presentation.request.oauth.OidcLoginRequest; | ||
import sorisoop.soridam.auth.jwt.application.JwtService; | ||
import sorisoop.soridam.auth.jwt.response.JwtResponse; | ||
import sorisoop.soridam.auth.oauth.google.GoogleOidcService; | ||
import sorisoop.soridam.auth.oauth.kakao.KakaoOidcService; | ||
import sorisoop.soridam.domain.user.domain.User; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class AuthFacade { | ||
private final KakaoOidcService kakaoOidcService; | ||
private final GoogleOidcService googleOidcService; | ||
private final JwtService jwtService; | ||
|
||
public JwtResponse jwtLogin(JwtLoginRequest request) { | ||
return jwtService.jwtLogin(request.email(), request.password()); | ||
} | ||
|
||
@Transactional | ||
public JwtResponse kakaoLogin(OidcLoginRequest idToken) { | ||
User user = kakaoOidcService.processLogin(idToken.idToken()); | ||
user.updateLastLoginTime(); | ||
return jwtService.getToken(user); | ||
} | ||
|
||
@Transactional | ||
public JwtResponse googleLogin(OidcLoginRequest idToken) { | ||
User user = googleOidcService.processLogin(idToken.idToken()); | ||
user.updateLastLoginTime(); | ||
return jwtService.getToken(user); | ||
} | ||
|
||
public JwtResponse reissue(RefreshTokenRequest request) { | ||
return jwtService.reissue(request.refreshToken()); | ||
} | ||
} |
This file was deleted.
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,15 @@ | ||||||||||||||
package sorisoop.soridam.api.auth.presentation.request.jwt; | ||||||||||||||
|
||||||||||||||
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; | ||||||||||||||
|
||||||||||||||
import io.swagger.v3.oas.annotations.media.Schema; | ||||||||||||||
import jakarta.validation.constraints.NotNull; | ||||||||||||||
|
||||||||||||||
public record RefreshTokenRequest( | ||||||||||||||
@Schema(description = "refresh token", | ||||||||||||||
example = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsILJdhDYTYzNzQwNjQwMH0.7J", | ||||||||||||||
requiredMode = REQUIRED) | ||||||||||||||
Comment on lines
+9
to
+11
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion API 문서의 예제 토큰 값 수정 필요 API 문서의 예제 값으로 실제 JWT 형식의 토큰을 사용하는 것은 보안상 좋지 않습니다. 대신 @Schema(description = "refresh token",
- example = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsILJdhDYTYzNzQwNjQwMH0.7J",
+ example = "example-refresh-token",
requiredMode = REQUIRED) 📝 Committable suggestion
Suggested change
|
||||||||||||||
@NotNull | ||||||||||||||
String refreshToken | ||||||||||||||
) { | ||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,12 @@ spring: | |
init: | ||
mode: always | ||
|
||
data: | ||
redis: | ||
host: ${REDIS_HOST:localhost} | ||
port: ${REDIS_PORT:6379} | ||
password: ${REDIS_PASSWORD} | ||
|
||
Comment on lines
+27
to
+32
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Codebase verification Redis 구성 경로 불일치 및 보안 설정 개선 필요 application.yml의 Redis 구성에 다음과 같은 문제가 있습니다:
다음과 같이 수정을 제안드립니다: - data:
+ spring:
+ data:
redis:
host: ${REDIS_HOST:localhost}
port: ${REDIS_PORT:6379}
password: ${REDIS_PASSWORD}
+ ssl:
+ enabled: ${REDIS_SSL_ENABLED:false} 🔗 Analysis chainRedis 구성의 보안 관련 개선사항 Redis 구성에서 다음 사항들을 고려해주시기 바랍니다:
다음과 같이 수정하는 것을 제안드립니다: data:
redis:
host: ${REDIS_HOST:localhost}
port: ${REDIS_PORT:6379}
- password: ${REDIS_PASSWORD}
+ password: ${REDIS_PASSWORD:}
+ ssl:
+ enabled: ${REDIS_SSL_ENABLED:false} 환경 변수가 설정되어 있는지 확인하기 위해 다음 스크립트를 실행해보세요: 🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Description: Check if Redis-related environment variables are set in various config files
echo "Checking for Redis environment variables in configuration files..."
rg -l "REDIS_(HOST|PORT|PASSWORD)"
Length of output: 226 Script: #!/bin/bash
# Search for Redis-related configurations in Java code and other config files
echo "Searching for Redis configuration in Java code..."
rg -t java "Redis" -A 5
echo -e "\nSearching for SSL/TLS configurations..."
rg "ssl" -i
Length of output: 6385 |
||
springdoc: | ||
default-consumes-media-type: application/json | ||
default-produces-media-type: application/json | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package sorisoop.soridam.auth.jwt.application; | ||
|
||
import org.springframework.stereotype.Service; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import sorisoop.soridam.auth.jwt.response.JwtResponse; | ||
import sorisoop.soridam.domain.refresh.RefreshToken; | ||
import sorisoop.soridam.domain.refresh.application.RefreshTokenService; | ||
import sorisoop.soridam.domain.user.application.UserCommandService; | ||
import sorisoop.soridam.domain.user.application.UserQueryService; | ||
import sorisoop.soridam.domain.user.domain.User; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class JwtService { | ||
private final UserQueryService userQueryService; | ||
private final UserCommandService userCommandService; | ||
private final RefreshTokenService refreshTokenService; | ||
private final JwtProvider jwtProvider; | ||
|
||
public JwtResponse jwtLogin(String email, String password) { | ||
User user = userCommandService.login(email, password); | ||
JwtResponse response = getToken(user); | ||
refreshTokenService.save(user.getId(), response.refreshToken()); | ||
return response; | ||
} | ||
|
||
public JwtResponse reissue(String token) { | ||
RefreshToken refreshToken = refreshTokenService.getToken(token); | ||
String userId = refreshToken.getUserId(); | ||
User user = userQueryService.getById(userId); | ||
JwtResponse response = getToken(user); | ||
|
||
refreshTokenService.delete(refreshToken); | ||
refreshTokenService.save(userId, response.refreshToken()); | ||
|
||
return response; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 리프레시 토큰 재발행 시 동시성 문제 가능성이 있습니다. 현재 구현에서는 이전 토큰 삭제와 새 토큰 저장이 원자적으로 실행되지 않습니다. 동시에 여러 요청이 들어올 경우 문제가 발생할 수 있습니다. 다음과 같은 개선을 제안드립니다: public JwtResponse reissue(String token) {
RefreshToken refreshToken = refreshTokenService.getToken(token);
String userId = refreshToken.getUserId();
User user = userQueryService.getById(userId);
JwtResponse response = getToken(user);
- refreshTokenService.delete(refreshToken);
- refreshTokenService.save(userId, response.refreshToken());
+ refreshTokenService.replaceToken(refreshToken, userId, response.refreshToken());
return response;
}
|
||
|
||
public JwtResponse getToken(User user) { | ||
String refreshToken = jwtProvider.generateRefreshToken(user.extractUuid(), user.getRole()); | ||
String accessToken = jwtProvider.generateAccessToken(user.extractUuid(), user.getRole()); | ||
|
||
return JwtResponse.of(accessToken, refreshToken); | ||
} | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
리프레시 토큰 재발행 API에 대한 문서화가 필요합니다.
다른 엔드포인트들과 같이
@Operation
과@ApiResponse
어노테이션을 추가하여 API 문서화를 해주세요.다음과 같이 추가하는 것을 제안드립니다:
📝 Committable suggestion