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 @@ -10,7 +10,7 @@
@AllArgsConstructor
public enum BigCategory {
CAFE("카페"),
ALCOHOL("주류"),
BAR("주류"),
RESTAURANT("음식점"),
EXPERIENCE("체험"),
CULTURE("문화생활"),
Expand Down
28 changes: 25 additions & 3 deletions src/main/java/umc/catchy/domain/jwt/domain/JwtTokenProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,21 @@ public class JwtTokenProvider {

private final JwtProperties jwtProperties;

public String createToken(String email, Long validity) {
public String createAccessToken(String refreshToken, Long validity) {
Claims claims = Jwts.claims().setSubject(refreshToken);
Date now = new Date();
Date expiryDate = new Date(now.getTime() + validity);

return Jwts.builder()
.setClaims(claims)
.setIssuedAt(now)
.setExpiration(expiryDate)
.signWith(SignatureAlgorithm.HS512, jwtProperties.getSecret())
.compact();

}

public String createRefreshToken(String email, Long validity) {
Claims claims = Jwts.claims().setSubject(email);
Date now = new Date();
Date expiryDate = new Date(now.getTime() + validity);
Expand Down Expand Up @@ -55,10 +69,18 @@ public boolean validateToken(String token) {
}
}

public String getEmailFromToken(String token) {
public String getEmailFromRefreshToken(String refreshToken) {
Claims claims = Jwts.parser()
.setSigningKey(jwtProperties.getSecret())
.parseClaimsJws(refreshToken)
.getBody();
return claims.getSubject();
}

public String getRefreshTokenFromAccessToken(String accessToken) {
Claims claims = Jwts.parser()
.setSigningKey(jwtProperties.getSecret())
.parseClaimsJws(token)
.parseClaimsJws(accessToken)
.getBody();
return claims.getSubject();
}
Expand Down
20 changes: 10 additions & 10 deletions src/main/java/umc/catchy/domain/jwt/service/RedisTokenService.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,27 @@ public class RedisTokenService {
private long EXPIRATION;

// 리프레시 토큰 저장
public void addRefreshToken(String refreshToken, Long memberId) {
String key = REDIS_REFRESH_TOKEN_KEY_PREFIX + memberId;
public void addRefreshToken(String refreshToken) {
String key = REDIS_REFRESH_TOKEN_KEY_PREFIX + refreshToken;
redisTemplate.opsForValue().set(key, refreshToken, EXPIRATION, TimeUnit.SECONDS);
}

// 리프레시 토큰 유효성 검사
public boolean isRefreshTokenValid(String refreshToken, Long memberId) {
String key = REDIS_REFRESH_TOKEN_KEY_PREFIX + memberId;
String storedToken = redisTemplate.opsForValue().get(key);
return storedToken != null && storedToken.equals(refreshToken);
public boolean isRefreshTokenValid(String refreshToken) {
String key = REDIS_REFRESH_TOKEN_KEY_PREFIX + refreshToken;
String storedUserId = redisTemplate.opsForValue().get(key);
return storedUserId != null;
}

// 리프레시 토큰 삭제
public void deleteRefreshToken(Long memberId) {
String key = REDIS_REFRESH_TOKEN_KEY_PREFIX + memberId;
public void deleteRefreshToken(String refreshToken) {
String key = REDIS_REFRESH_TOKEN_KEY_PREFIX + refreshToken;
redisTemplate.delete(key);
}

// 리프레시 토큰 찾기
public String getRefreshToken(Long memberId) {
String key = REDIS_REFRESH_TOKEN_KEY_PREFIX + memberId;
public String getRefreshToken(String refreshToken) {
String key = REDIS_REFRESH_TOKEN_KEY_PREFIX + refreshToken;
return redisTemplate.opsForValue().get(key);
}
}
38 changes: 18 additions & 20 deletions src/main/java/umc/catchy/domain/member/service/MemberService.java
Original file line number Diff line number Diff line change
Expand Up @@ -209,14 +209,14 @@ public SignUpResponse signUp(SignUpRequest request, MultipartFile profileImage,
}

// 토큰 발급
String accessToken = jwtUtil.createAccessToken(newMember.getEmail());
String refreshToken = jwtUtil.createRefreshToken(newMember.getEmail());
String accessToken = jwtUtil.createAccessToken(refreshToken);

// 액세스 토큰 DB 저장
newMember.setAccessToken(accessToken);

// 리프레시 토큰 redis 저장
redisTokenService.addRefreshToken(refreshToken, newMember.getId());
redisTokenService.addRefreshToken(refreshToken);

memberRepository.save(newMember);

Expand All @@ -233,48 +233,43 @@ public LoginResponse login(LoginRequest request, SocialType socialType) {
Member member = optionalMember.orElseThrow(() ->
new GeneralException(ErrorStatus.MEMBER_NOT_FOUND));

// 기존 리프레시 토큰 삭제
redisTokenService.deleteRefreshToken(member.getId());

// 토큰 발급
String accessToken = jwtUtil.createAccessToken(member.getEmail());
String refreshToken = jwtUtil.createRefreshToken(member.getEmail());
String accessToken = jwtUtil.createAccessToken(refreshToken);

// 액세스 토큰 DB 저장
member.setAccessToken(accessToken);

// 리프레시 토큰 redis 저장
redisTokenService.addRefreshToken(refreshToken, member.getId());
redisTokenService.addRefreshToken(refreshToken);

return LoginResponse.of(member, accessToken, refreshToken);
}

public ReIssueTokenResponse validateRefreshToken() {
String refreshToken = SecurityUtil.extractRefreshToken();
Long memberId = SecurityUtil.getCurrentMemberId();
Member member = memberRepository.findById(memberId)
.orElseThrow(() -> new GeneralException(ErrorStatus.MEMBER_NOT_FOUND));

if (refreshToken == null) throw new GeneralException(ErrorStatus.NOT_FOUND_TOKEN);

// 리프레시 토큰 만료 검사
boolean isValid = redisTokenService.isRefreshTokenValid(refreshToken, memberId);
boolean isValid = redisTokenService.isRefreshTokenValid(refreshToken);

// 리프레시 토큰이 유효할 때
if (isValid) {
// 기존 토큰들 무효화
String email = jwtUtil.getEmailFromToken(refreshToken);
Member member = memberRepository.findByEmail(email)
.orElseThrow(() -> new GeneralException(ErrorStatus.MEMBER_NOT_FOUND));
String originAccessToken = member.getAccessToken();
long expirationTime = jwtUtil.getExpirationTime(originAccessToken).getTime() - System.currentTimeMillis();
blackTokenRedisService.addBlacklistedToken(originAccessToken, expirationTime);
redisTokenService.deleteRefreshToken(member.getId());

// 액세스 토큰 재발급
String newAccessToken = jwtUtil.createAccessToken(member.getEmail());
String newRefreshToken = jwtUtil.createRefreshToken(member.getEmail());
redisTokenService.deleteRefreshToken(refreshToken);

member.setAccessToken(newAccessToken);
// 토큰 재발급
String newRefreshToken = jwtUtil.createRefreshToken(email);
String newAccessToken = jwtUtil.createAccessToken(refreshToken);

redisTokenService.addRefreshToken(newRefreshToken, member.getId());
redisTokenService.addRefreshToken(newRefreshToken);

return ReIssueTokenResponse.of(newAccessToken, newRefreshToken);
}
Expand Down Expand Up @@ -406,6 +401,7 @@ public void withdraw(String authorizationCode) {
Long memberId = SecurityUtil.getCurrentMemberId();
Member member = memberRepository.findById(memberId).orElseThrow(() ->
new GeneralException(ErrorStatus.MEMBER_NOT_FOUND));
String refreshToken = SecurityUtil.extractRefreshToken();

if (member.getSocialType() == SocialType.APPLE) {

Expand Down Expand Up @@ -438,7 +434,7 @@ public void withdraw(String authorizationCode) {
String originAccessToken = member.getAccessToken();
long expirationTime = jwtUtil.getExpirationTime(originAccessToken).getTime() - System.currentTimeMillis();
blackTokenRedisService.addBlacklistedToken(originAccessToken, expirationTime);
redisTokenService.deleteRefreshToken(member.getId());
redisTokenService.deleteRefreshToken(refreshToken);

memberRepository.delete(member);
}
Expand All @@ -448,14 +444,16 @@ public void logout() {
Member member = memberRepository.findById(memberId).orElseThrow(() ->
new GeneralException(ErrorStatus.MEMBER_NOT_FOUND));

String refreshToken = SecurityUtil.extractRefreshToken();

// JWT 블랙리스트에 추가
Date expirationTime = jwtUtil.getExpirationTime(member.getAccessToken());

// 액세스 토큰 만료
blackTokenRedisService.addBlacklistedToken(member.getAccessToken(), expirationTime.getTime() - System.currentTimeMillis());

// redis 리프레시 토큰 삭제
redisTokenService.deleteRefreshToken(memberId);
redisTokenService.deleteRefreshToken(refreshToken);
member.deleteFcmToken(member.getFcmInfo());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
, "/member/signup/**","/group/invite/**"
, "/member/reissue", "/member/callback/**"
,"/course/generate-ai", "/health"
,"/course/place/current", "/course/place/region").permitAll()
,"/course/place/current", "/course/place/region"
, "/member/mypage/nickname").permitAll()
.anyRequest().authenticated()
)
.exceptionHandling(exception -> exception
Expand Down
12 changes: 8 additions & 4 deletions src/main/java/umc/catchy/global/util/JwtUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,24 @@ public class JwtUtil {
private final JwtProperties jwtProperties;
private final MemberRepository memberRepository;

public String createAccessToken(String email) {
return jwtTokenProvider.createToken(email, jwtProperties.getAccessTokenValidity());
public String createAccessToken(String refreshToken) {
return jwtTokenProvider.createAccessToken(refreshToken, jwtProperties.getAccessTokenValidity());
}

public String createRefreshToken(String email) {
return jwtTokenProvider.createToken(email, jwtProperties.getRefreshTokenValidity());
return jwtTokenProvider.createRefreshToken(email, jwtProperties.getRefreshTokenValidity());
}

public boolean validateToken(String token) {
return jwtTokenProvider.validateToken(token);
}

public String getEmailFromToken(String token) {
return jwtTokenProvider.getEmailFromToken(token);
return jwtTokenProvider.getEmailFromRefreshToken(token);
}

public String getRefreshTokenFromToken(String token) {
return jwtTokenProvider.getRefreshTokenFromAccessToken(token);
}

public Long getMemberIdFromToken(String token) {
Expand Down