diff --git a/src/main/java/com/api/tokbaro/domain/apns/service/ApnsServiceImpl.java b/src/main/java/com/api/tokbaro/domain/apns/service/ApnsServiceImpl.java index 5d5cd2c..1bebc0d 100644 --- a/src/main/java/com/api/tokbaro/domain/apns/service/ApnsServiceImpl.java +++ b/src/main/java/com/api/tokbaro/domain/apns/service/ApnsServiceImpl.java @@ -4,7 +4,6 @@ import com.api.tokbaro.domain.apns.web.dto.ApnsRes; import com.api.tokbaro.domain.apns.web.dto.StateReq; import com.eatthepath.pushy.apns.*; -import com.eatthepath.pushy.apns.util.SimpleApnsPushNotification; import com.eatthepath.pushy.apns.util.TokenUtil; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/src/main/java/com/api/tokbaro/domain/auth/service/AuthService.java b/src/main/java/com/api/tokbaro/domain/auth/service/AuthService.java index a23884d..e02797e 100644 --- a/src/main/java/com/api/tokbaro/domain/auth/service/AuthService.java +++ b/src/main/java/com/api/tokbaro/domain/auth/service/AuthService.java @@ -6,5 +6,5 @@ public interface AuthService { SignInUserRes signIn(SignInUserReq signInUserReq); AppleLoginRes appleLogin(AppleIdReq appleIdReq); SignInUserRes reissue(ReissueReq reissueReq); - void logout(Long userId, String token); + void logout(Long userId, String authorizationHeader); } diff --git a/src/main/java/com/api/tokbaro/domain/auth/service/AuthServiceImpl.java b/src/main/java/com/api/tokbaro/domain/auth/service/AuthServiceImpl.java index 7ac660e..8fdc1d1 100644 --- a/src/main/java/com/api/tokbaro/domain/auth/service/AuthServiceImpl.java +++ b/src/main/java/com/api/tokbaro/domain/auth/service/AuthServiceImpl.java @@ -1,10 +1,10 @@ package com.api.tokbaro.domain.auth.service; import com.api.tokbaro.domain.auth.web.dto.*; -import com.api.tokbaro.domain.user.entity.Role; import com.api.tokbaro.domain.user.entity.User; import com.api.tokbaro.domain.user.repository.UserRepository; import com.api.tokbaro.domain.user.service.UserService; +import com.api.tokbaro.global.constant.StaticValue; import com.api.tokbaro.global.exception.CustomException; import com.api.tokbaro.global.jwt.AppleJwtVerifier; import com.api.tokbaro.global.jwt.JwtTokenProvider; @@ -37,7 +37,6 @@ public class AuthServiceImpl implements AuthService { private final AppleJwtVerifier appleJwtVerifier; private final UserService userService; private final RedisService redisService; - private static final String REFRESH_TOKEN_KEY_PREFIX = "RT:"; //일반 로그인 @Override @@ -53,7 +52,7 @@ public SignInUserRes signIn(SignInUserReq signInUserReq) { User user = userRepository.findById(userPrincipal.getId()) .orElseThrow(()->new CustomException(UserErrorResponseCode.USER_NOT_FOUND_404)); - redisService.setValue(REFRESH_TOKEN_KEY_PREFIX + user.getId(), tokens.refreshToken(), Duration.ofMillis(jwtTokenProvider.getRefreshTokenValidity())); + redisService.setValue(StaticValue.REFRESH_TOKEN_KEY_PREFIX + user.getId(), tokens.refreshToken(), Duration.ofMillis(jwtTokenProvider.getRefreshTokenValidity())); return tokens; } @@ -106,7 +105,7 @@ public AppleLoginRes appleLogin(AppleIdReq appleIdReq) { //accessToken, refresh토큰 생성 SignInUserRes tokens = jwtTokenProvider.createTokens(authentication); - redisService.setValue(REFRESH_TOKEN_KEY_PREFIX + user.getId(), tokens.refreshToken(), + redisService.setValue(StaticValue.REFRESH_TOKEN_KEY_PREFIX + user.getId(), tokens.refreshToken(), Duration.ofMillis(jwtTokenProvider.getRefreshTokenValidity())); return AppleLoginRes.builder() .grantType(tokens.grantType()) @@ -127,7 +126,7 @@ public SignInUserRes reissue(ReissueReq reissueReq) { //2. RefreshToken으로 사용자 ID 추출 및 Redis에서 검증 Long userId = jwtTokenProvider.getUserIdFromToken(reissueReq.getRefreshToken()); - String storedRefreshToken = redisService.getValue(REFRESH_TOKEN_KEY_PREFIX + userId); + String storedRefreshToken = redisService.getValue(StaticValue.REFRESH_TOKEN_KEY_PREFIX + userId); if(storedRefreshToken == null || !storedRefreshToken.equals(reissueReq.getRefreshToken())){ throw new CustomException(UserErrorResponseCode.INVALID_REFRESH_TOKEN_401); @@ -144,7 +143,7 @@ public SignInUserRes reissue(ReissueReq reissueReq) { Collections.singleton(new SimpleGrantedAuthority("ROLE_" + user.getRole().name())) ); - redisService.deleteValue(REFRESH_TOKEN_KEY_PREFIX + userId); + redisService.deleteValue(StaticValue.REFRESH_TOKEN_KEY_PREFIX + userId); Authentication authentication = new UsernamePasswordAuthenticationToken( userPrincipal, @@ -153,7 +152,7 @@ public SignInUserRes reissue(ReissueReq reissueReq) { //새로운 토큰 생성 SignInUserRes newTokens = jwtTokenProvider.createTokens(authentication); - redisService.setValue(REFRESH_TOKEN_KEY_PREFIX + user.getId(), newTokens.refreshToken(), Duration.ofMillis(jwtTokenProvider.getRefreshTokenValidity())); + redisService.setValue(StaticValue.REFRESH_TOKEN_KEY_PREFIX + user.getId(), newTokens.refreshToken(), Duration.ofMillis(jwtTokenProvider.getRefreshTokenValidity())); return newTokens; } @@ -161,13 +160,15 @@ public SignInUserRes reissue(ReissueReq reissueReq) { //로그아웃 @Override @Transactional - public void logout(Long userId, String accessToken) { + public void logout(Long userId, String authorizationHeader) { User user = userRepository.findById(userId) .orElseThrow(()->new CustomException(UserErrorResponseCode.USER_NOT_FOUND_404)); log.info("로그아웃 요청 사용자: {}", user.getUsername()); - redisService.deleteValue(REFRESH_TOKEN_KEY_PREFIX + userId); + String accessToken = authorizationHeader.substring(StaticValue.BEARER_PREFIX.length()); + + redisService.deleteValue(StaticValue.REFRESH_TOKEN_KEY_PREFIX + userId); log.info("Redis에서 사용자 {}의 Refresh Token을 제거 하였습니다.", user.getUsername()); Long expiration = jwtTokenProvider.getExpiration(accessToken); diff --git a/src/main/java/com/api/tokbaro/domain/auth/web/controller/AuthController.java b/src/main/java/com/api/tokbaro/domain/auth/web/controller/AuthController.java index 868e387..1ee6e1b 100644 --- a/src/main/java/com/api/tokbaro/domain/auth/web/controller/AuthController.java +++ b/src/main/java/com/api/tokbaro/domain/auth/web/controller/AuthController.java @@ -34,8 +34,8 @@ public ResponseEntity> signIn(@RequestBody SignInUserReq sign @PostMapping("/logout") public ResponseEntity> logout(@AuthenticationPrincipal UserPrincipal userPrincipal, @RequestHeader("Authorization")String authorizationHeader) { - String accessToken = authorizationHeader.substring(JwtExtractor.BEARER_PREFIX.length()); - authService.logout(userPrincipal.getId(),accessToken); + + authService.logout(userPrincipal.getId(),authorizationHeader); return ResponseEntity .status(HttpStatus.OK) .body(SuccessResponse.emptyCustom("로그아웃에 성공하였습니다.")); diff --git a/src/main/java/com/api/tokbaro/domain/content/service/ContentDataService.java b/src/main/java/com/api/tokbaro/domain/content/service/ContentDataService.java index 95755ab..2a1f4b0 100644 --- a/src/main/java/com/api/tokbaro/domain/content/service/ContentDataService.java +++ b/src/main/java/com/api/tokbaro/domain/content/service/ContentDataService.java @@ -5,7 +5,6 @@ import com.api.tokbaro.domain.apns.web.dto.StateReq; import com.api.tokbaro.domain.content.web.dto.ReactionReq; import com.api.tokbaro.domain.content.web.dto.ReactionVelocityRes; -import com.api.tokbaro.global.jwt.UserPrincipal; import java.util.List; diff --git a/src/main/java/com/api/tokbaro/domain/user/service/UserService.java b/src/main/java/com/api/tokbaro/domain/user/service/UserService.java index c41f493..5156d22 100644 --- a/src/main/java/com/api/tokbaro/domain/user/service/UserService.java +++ b/src/main/java/com/api/tokbaro/domain/user/service/UserService.java @@ -12,5 +12,5 @@ public interface UserService { MyInfoRes getMyInfo(Long userId); - void deleteUser(Long userId, String accessToken); + void deleteUser(Long userId, String authorizationHeader); } diff --git a/src/main/java/com/api/tokbaro/domain/user/service/UserServiceImpl.java b/src/main/java/com/api/tokbaro/domain/user/service/UserServiceImpl.java index 4458100..b9c0605 100644 --- a/src/main/java/com/api/tokbaro/domain/user/service/UserServiceImpl.java +++ b/src/main/java/com/api/tokbaro/domain/user/service/UserServiceImpl.java @@ -1,14 +1,10 @@ package com.api.tokbaro.domain.user.service; -import com.api.tokbaro.domain.apns.service.ApnsService; -import com.api.tokbaro.domain.apns.web.dto.ApnsRes; -import com.api.tokbaro.domain.apns.web.dto.StateReq; -import com.api.tokbaro.domain.content.entity.ContentData; -import com.api.tokbaro.domain.content.repository.ContentDataRepository; import com.api.tokbaro.domain.user.entity.Role; import com.api.tokbaro.domain.user.entity.User; import com.api.tokbaro.domain.user.repository.UserRepository; import com.api.tokbaro.domain.user.web.dto.*; +import com.api.tokbaro.global.constant.StaticValue; import com.api.tokbaro.global.exception.CustomException; import com.api.tokbaro.global.jwt.JwtTokenProvider; import com.api.tokbaro.global.redis.RedisService; @@ -27,8 +23,6 @@ public class UserServiceImpl implements UserService { private final UserRepository userRepository; private final PasswordEncoder passwordEncoder; - private final ContentDataRepository contentDataRepository; - private final ApnsService apnsService; private final JwtTokenProvider jwtTokenProvider; private final RedisService redisService; @@ -82,14 +76,17 @@ public MyInfoRes getMyInfo(Long userId) { @Override @Transactional - public void deleteUser(Long userId, String accessToken) { + public void deleteUser(Long userId, String authorizationHeader) { User user = userRepository.findById(userId) .orElseThrow(() -> new CustomException(UserErrorResponseCode.USER_NOT_FOUND_404)); log.info("회원 탈퇴 요청 사용자 : {}", user.getUsername()); + + String accessToken = authorizationHeader.substring(StaticValue.BEARER_PREFIX.length()); + Long expiration = jwtTokenProvider.getExpiration(accessToken); redisService.addTokenToBlacklist(accessToken, expiration); - redisService.deleteValue("RT:" + user.getId()); + redisService.deleteValue(StaticValue.REFRESH_TOKEN_KEY_PREFIX + user.getId()); log.info("액세스 토큰이 블랙리스트에 추가 되었습니다. (만료시간 : {}초)", expiration); userRepository.delete(user); diff --git a/src/main/java/com/api/tokbaro/domain/user/web/controller/UserController.java b/src/main/java/com/api/tokbaro/domain/user/web/controller/UserController.java index 3c75b23..47baa11 100644 --- a/src/main/java/com/api/tokbaro/domain/user/web/controller/UserController.java +++ b/src/main/java/com/api/tokbaro/domain/user/web/controller/UserController.java @@ -3,19 +3,13 @@ import com.api.tokbaro.domain.user.service.UserService; import com.api.tokbaro.domain.user.web.dto.*; import com.api.tokbaro.global.jwt.JwtExtractor; -import com.api.tokbaro.global.jwt.JwtTokenProvider; import com.api.tokbaro.global.jwt.UserPrincipal; import com.api.tokbaro.global.response.SuccessResponse; -import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.core.Authentication; import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.security.core.parameters.P; import org.springframework.web.bind.annotation.*; @RestController @@ -25,7 +19,6 @@ public class UserController { private final UserService userService; - private final JwtExtractor jwtExtractor; //회원가입 @PostMapping("/users") @@ -49,8 +42,7 @@ public ResponseEntity> getMyInfo(@AuthenticationPrincipal Use @DeleteMapping("/users") public ResponseEntity> deleteUser(@AuthenticationPrincipal UserPrincipal userPrincipal, @RequestHeader("Authorization")String authorizationHeader){ - String accessToken = authorizationHeader.substring(JwtExtractor.BEARER_PREFIX.length()); - userService.deleteUser(userPrincipal.getId(), accessToken); + userService.deleteUser(userPrincipal.getId(), authorizationHeader); return ResponseEntity .status(HttpStatus.OK) .body(SuccessResponse.okCustom(null,"회원탈퇴에 성공하였습니다")); diff --git a/src/main/java/com/api/tokbaro/global/constant/StaticValue.java b/src/main/java/com/api/tokbaro/global/constant/StaticValue.java index e62d7ce..251a940 100644 --- a/src/main/java/com/api/tokbaro/global/constant/StaticValue.java +++ b/src/main/java/com/api/tokbaro/global/constant/StaticValue.java @@ -13,4 +13,10 @@ public class StaticValue { // 공통 응답 enum 정의 클래스 public static final int METHOD_NOT_ALLOWED = 405; // 허용되지 않는 메서드 public static final int CONFLICT = 409; // 충돌 발생 public static final int INTERNAL_SERVER_ERROR = 500; // 서버 내부 오류 + + //JWT and Security Constants + public static final String AUTHORIZATION_HEADER = "Authorization"; + public static final String BEARER_PREFIX = "Bearer "; + public static final String ID_CLAIM_KEY = "id"; + public static final String REFRESH_TOKEN_KEY_PREFIX = "RT:"; } diff --git a/src/main/java/com/api/tokbaro/global/jwt/JwtExtractor.java b/src/main/java/com/api/tokbaro/global/jwt/JwtExtractor.java index 03bb124..ff18472 100644 --- a/src/main/java/com/api/tokbaro/global/jwt/JwtExtractor.java +++ b/src/main/java/com/api/tokbaro/global/jwt/JwtExtractor.java @@ -1,5 +1,6 @@ package com.api.tokbaro.global.jwt; +import com.api.tokbaro.global.constant.StaticValue; import jakarta.servlet.http.HttpServletRequest; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; @@ -7,13 +8,10 @@ @Component public class JwtExtractor { - public static final String AUTHORIZATION_HEADER = "Authorization"; - public static final String BEARER_PREFIX = "Bearer "; - public String extractAccessToken(HttpServletRequest request) { - String bearerToken = request.getHeader(AUTHORIZATION_HEADER); - if(StringUtils.hasText(bearerToken) && bearerToken.startsWith(BEARER_PREFIX)) { - return bearerToken.substring(BEARER_PREFIX.length()); + String bearerToken = request.getHeader(StaticValue.AUTHORIZATION_HEADER); + if(StringUtils.hasText(bearerToken) && bearerToken.startsWith(StaticValue.BEARER_PREFIX)) { + return bearerToken.substring(StaticValue.BEARER_PREFIX.length()); } return null; } diff --git a/src/main/java/com/api/tokbaro/global/jwt/JwtTokenProvider.java b/src/main/java/com/api/tokbaro/global/jwt/JwtTokenProvider.java index aedb3ce..22f9bf1 100644 --- a/src/main/java/com/api/tokbaro/global/jwt/JwtTokenProvider.java +++ b/src/main/java/com/api/tokbaro/global/jwt/JwtTokenProvider.java @@ -111,13 +111,13 @@ public boolean validateToken(String token){ .parseClaimsJws(token); return true; } catch (io.jsonwebtoken.security.SignatureException | MalformedJwtException e){ - logger.info("잘못된 JWT 서명입니다."); + logger.warn("잘못된 JWT 서명입니다."); } catch (ExpiredJwtException e){ - logger.info("만료된 JWT 토큰입니다."); + logger.warn("만료된 JWT 토큰입니다."); } catch (UnsupportedJwtException e){ - logger.info("지원되지 않는 JWT 토큰입니다."); + logger.warn("지원되지 않는 JWT 토큰입니다."); } catch (IllegalArgumentException e){ - logger.info("JWT 토큰이 잘못되었습니다."); + logger.warn("JWT 토큰이 잘못되었습니다."); } return false; } diff --git a/src/main/resources/application-local.properties b/src/main/resources/application-local.properties deleted file mode 100644 index 6c9e2af..0000000 --- a/src/main/resources/application-local.properties +++ /dev/null @@ -1,33 +0,0 @@ -spring.application.name=Tokbaro - - -logging.level.com.api.tokbaro=DEBUG -# Datasource(MySQL) -spring.datasource.url=${DATABASE_URL} -spring.datasource.username=${DATABASE_USERNAME} -spring.datasource.password=${DATABASE_PASSWORD} - -# JWT -security.jwt.secret-key=${JWT_SECRET_KEY} -security.jwt.access-expiration=${JWT_ACCESS_EXPIRATION} -security.jwt.refresh-expiration=${JWT_REFRESH_EXPIRATION} - -# JPA -spring.jpa.hibernate.ddl-auto=update -spring.jpa.show-sql=false -spring.jpa.properties.hibernate.format_sql=false -spring.jpa.properties.hibernate.use_sql_comments=false -spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect - -#apns -apns.team-id=${APNS_TEAM_ID} -apns.key-id=${APNS_KEY_ID} -apns.bundle-id=${APNS_BUNDLE_ID} -apns.p8-file-path=${APNS_P8_FILE} - -#apple Login -apple.client-id=${APPLE_CLIENT_ID} - -#Redis -spring.data.redis.host=${REDIS_HOST} -spring.data.redis.port=${REDIS_PORT} \ No newline at end of file