diff --git a/src/main/java/umc/catchy/domain/category/domain/BigCategory.java b/src/main/java/umc/catchy/domain/category/domain/BigCategory.java index 140d1a16..0126ef62 100644 --- a/src/main/java/umc/catchy/domain/category/domain/BigCategory.java +++ b/src/main/java/umc/catchy/domain/category/domain/BigCategory.java @@ -10,7 +10,7 @@ @AllArgsConstructor public enum BigCategory { CAFE("카페"), - ALCOHOL("주류"), + BAR("주류"), RESTAURANT("음식점"), EXPERIENCE("체험"), CULTURE("문화생활"), diff --git a/src/main/java/umc/catchy/domain/jwt/domain/JwtTokenProvider.java b/src/main/java/umc/catchy/domain/jwt/domain/JwtTokenProvider.java index f4103b2d..9a244130 100644 --- a/src/main/java/umc/catchy/domain/jwt/domain/JwtTokenProvider.java +++ b/src/main/java/umc/catchy/domain/jwt/domain/JwtTokenProvider.java @@ -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); @@ -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(); } diff --git a/src/main/java/umc/catchy/domain/jwt/service/RedisTokenService.java b/src/main/java/umc/catchy/domain/jwt/service/RedisTokenService.java index b9213b47..edcac5d6 100644 --- a/src/main/java/umc/catchy/domain/jwt/service/RedisTokenService.java +++ b/src/main/java/umc/catchy/domain/jwt/service/RedisTokenService.java @@ -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); } } diff --git a/src/main/java/umc/catchy/domain/member/service/MemberService.java b/src/main/java/umc/catchy/domain/member/service/MemberService.java index e811c5ed..16c2f3c7 100644 --- a/src/main/java/umc/catchy/domain/member/service/MemberService.java +++ b/src/main/java/umc/catchy/domain/member/service/MemberService.java @@ -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); @@ -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); } @@ -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) { @@ -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); } @@ -448,6 +444,8 @@ 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()); @@ -455,7 +453,7 @@ public void logout() { blackTokenRedisService.addBlacklistedToken(member.getAccessToken(), expirationTime.getTime() - System.currentTimeMillis()); // redis 리프레시 토큰 삭제 - redisTokenService.deleteRefreshToken(memberId); + redisTokenService.deleteRefreshToken(refreshToken); member.deleteFcmToken(member.getFcmInfo()); } diff --git a/src/main/java/umc/catchy/global/config/security/SecurityConfig.java b/src/main/java/umc/catchy/global/config/security/SecurityConfig.java index d6f37bdd..1f97276d 100644 --- a/src/main/java/umc/catchy/global/config/security/SecurityConfig.java +++ b/src/main/java/umc/catchy/global/config/security/SecurityConfig.java @@ -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 diff --git a/src/main/java/umc/catchy/global/util/JwtUtil.java b/src/main/java/umc/catchy/global/util/JwtUtil.java index f7474e1e..d2174c10 100644 --- a/src/main/java/umc/catchy/global/util/JwtUtil.java +++ b/src/main/java/umc/catchy/global/util/JwtUtil.java @@ -19,12 +19,12 @@ 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) { @@ -32,7 +32,11 @@ public boolean validateToken(String 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) {