diff --git a/hous-api/build.gradle b/hous-api/build.gradle index 60362683..f5d6a0c6 100644 --- a/hous-api/build.gradle +++ b/hous-api/build.gradle @@ -11,15 +11,10 @@ dependencies { implementation "org.springframework.boot:spring-boot-starter-data-redis" implementation "org.springframework.session:spring-session-data-redis" runtimeOnly "mysql:mysql-connector-java" - implementation group: "io.jsonwebtoken", name: "jjwt-api", version: "0.11.2" - implementation group: "io.jsonwebtoken", name: "jjwt-impl", version: "0.11.2" - implementation group: "io.jsonwebtoken", name: "jjwt-jackson", version: "0.11.2" implementation "org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE" implementation group: "io.springfox", name: "springfox-swagger-ui", version: "2.9.2" implementation group: "io.springfox", name: "springfox-swagger2", version: "2.9.2" implementation "org.springframework.cloud:spring-cloud-starter-openfeign" - implementation "com.google.firebase:firebase-admin:6.8.1" - implementation group: "com.squareup.okhttp3", name: "okhttp", version: "4.2.2" implementation "com.slack.api:slack-api-client:1.25.1" testImplementation "org.springframework.security:spring-security-test" } diff --git a/hous-api/src/main/java/hous/api/config/interceptor/auth/AuthInterceptor.java b/hous-api/src/main/java/hous/api/config/interceptor/auth/AuthInterceptor.java index 113bd5d0..82950a3e 100644 --- a/hous-api/src/main/java/hous/api/config/interceptor/auth/AuthInterceptor.java +++ b/hous-api/src/main/java/hous/api/config/interceptor/auth/AuthInterceptor.java @@ -7,7 +7,7 @@ import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; -import hous.api.config.security.JwtConstants; +import hous.common.constant.JwtKeys; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor @@ -28,7 +28,7 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons return true; } Long userId = loginCheckHandler.getUserId(request); - request.setAttribute(JwtConstants.USER_ID, userId); + request.setAttribute(JwtKeys.USER_ID, userId); return true; } } diff --git a/hous-api/src/main/java/hous/api/config/interceptor/auth/LoginCheckHandler.java b/hous-api/src/main/java/hous/api/config/interceptor/auth/LoginCheckHandler.java index 7c530e4f..5d95ae5b 100644 --- a/hous-api/src/main/java/hous/api/config/interceptor/auth/LoginCheckHandler.java +++ b/hous-api/src/main/java/hous/api/config/interceptor/auth/LoginCheckHandler.java @@ -5,22 +5,22 @@ import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; -import hous.api.service.jwt.JwtService; import hous.common.exception.UnAuthorizedException; +import hous.common.util.JwtUtils; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor @Component public class LoginCheckHandler { - private final JwtService jwtService; + private final JwtUtils jwtUtils; public Long getUserId(HttpServletRequest request) { String bearerToken = request.getHeader("Authorization"); if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { String accessToken = bearerToken.substring("Bearer ".length()); - if (jwtService.validateToken(accessToken)) { - Long userId = jwtService.getUserIdFromJwt(accessToken); + if (jwtUtils.validateToken(accessToken)) { + Long userId = jwtUtils.getUserIdFromJwt(accessToken); if (userId != null) { return userId; } diff --git a/hous-api/src/main/java/hous/api/config/resolver/UserIdResolver.java b/hous-api/src/main/java/hous/api/config/resolver/UserIdResolver.java index 78d9dce0..f250b217 100644 --- a/hous-api/src/main/java/hous/api/config/resolver/UserIdResolver.java +++ b/hous-api/src/main/java/hous/api/config/resolver/UserIdResolver.java @@ -9,7 +9,7 @@ import org.springframework.web.method.support.ModelAndViewContainer; import hous.api.config.interceptor.auth.Auth; -import hous.api.config.security.JwtConstants; +import hous.common.constant.JwtKeys; import hous.common.exception.InternalServerException; @Component @@ -27,7 +27,7 @@ public Object resolveArgument(@NotNull MethodParameter parameter, ModelAndViewCo if (parameter.getMethodAnnotation(Auth.class) == null) { throw new InternalServerException("인증이 필요한 컨트롤러 입니다. @Auth 어노테이션을 붙여주세요."); } - Object object = webRequest.getAttribute(JwtConstants.USER_ID, 0); + Object object = webRequest.getAttribute(JwtKeys.USER_ID, 0); if (object == null) { throw new InternalServerException( String.format("USER_ID를 가져오지 못했습니다. (%s - %s)", parameter.getClass(), parameter.getMethod())); diff --git a/hous-api/src/main/java/hous/api/service/auth/CommonAuthService.java b/hous-api/src/main/java/hous/api/service/auth/CommonAuthService.java index 95d3ca65..63cb4fe5 100644 --- a/hous-api/src/main/java/hous/api/service/auth/CommonAuthService.java +++ b/hous-api/src/main/java/hous/api/service/auth/CommonAuthService.java @@ -4,8 +4,8 @@ import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; -import hous.api.service.jwt.JwtService; import hous.api.service.user.UserServiceUtils; +import hous.common.util.JwtUtils; import hous.core.domain.user.User; import hous.core.domain.user.mysql.UserRepository; import lombok.RequiredArgsConstructor; @@ -17,11 +17,11 @@ public class CommonAuthService { private final UserRepository userRepository; - private final JwtService jwtService; + private final JwtUtils jwtUtils; public void logout(Long userId) { User user = UserServiceUtils.findUserById(userRepository, userId); - jwtService.expireRefreshToken(user.getId()); + jwtUtils.expireRefreshToken(user.getId()); user.resetFcmToken(); } @@ -29,7 +29,7 @@ public void logout(Long userId) { public void resetConflictFcmToken(String fcmToken) { User conflictFcmTokenUser = userRepository.findUserByFcmToken(fcmToken); if (conflictFcmTokenUser != null) { - jwtService.expireRefreshToken(conflictFcmTokenUser.getId()); + jwtUtils.expireRefreshToken(conflictFcmTokenUser.getId()); conflictFcmTokenUser.resetFcmToken(); } } diff --git a/hous-api/src/main/java/hous/api/service/auth/CommonAuthServiceUtils.java b/hous-api/src/main/java/hous/api/service/auth/CommonAuthServiceUtils.java index 52b779ed..3aaf9d93 100644 --- a/hous-api/src/main/java/hous/api/service/auth/CommonAuthServiceUtils.java +++ b/hous-api/src/main/java/hous/api/service/auth/CommonAuthServiceUtils.java @@ -4,9 +4,9 @@ import org.springframework.data.redis.core.RedisTemplate; -import hous.api.service.jwt.JwtService; import hous.common.constant.RedisKey; import hous.common.exception.ConflictException; +import hous.common.util.JwtUtils; import hous.core.domain.user.User; import lombok.AccessLevel; import lombok.NoArgsConstructor; @@ -21,7 +21,7 @@ public static void validateUniqueLogin(RedisTemplate redisTempla } } - public static void forceLogoutUser(RedisTemplate redisTemplate, JwtService jwtService, User user) { + public static void forceLogoutUser(RedisTemplate redisTemplate, JwtUtils jwtService, User user) { String refreshToken = (String)redisTemplate.opsForValue().get(RedisKey.REFRESH_TOKEN + user.getId()); if (refreshToken != null) { jwtService.expireRefreshToken(user.getId()); diff --git a/hous-api/src/main/java/hous/api/service/auth/CreateTokenService.java b/hous-api/src/main/java/hous/api/service/auth/CreateTokenService.java index 13575b28..4cf5fc3c 100644 --- a/hous-api/src/main/java/hous/api/service/auth/CreateTokenService.java +++ b/hous-api/src/main/java/hous/api/service/auth/CreateTokenService.java @@ -1,5 +1,6 @@ package hous.api.service.auth; +import java.util.List; import java.util.Objects; import org.springframework.data.redis.core.RedisTemplate; @@ -9,11 +10,11 @@ import hous.api.service.auth.dto.request.TokenRequestDto; import hous.api.service.auth.dto.response.RefreshResponse; import hous.api.service.auth.dto.response.TokenResponse; -import hous.api.service.jwt.JwtService; import hous.api.service.room.RoomService; import hous.api.service.user.UserServiceUtils; import hous.common.constant.RedisKey; import hous.common.exception.UnAuthorizedException; +import hous.common.util.JwtUtils; import hous.core.domain.user.User; import hous.core.domain.user.mysql.UserRepository; import lombok.RequiredArgsConstructor; @@ -26,19 +27,20 @@ public class CreateTokenService { private final RedisTemplate redisTemplate; - private final JwtService jwtService; + private final JwtUtils jwtUtils; private final RoomService roomService; @Transactional public TokenResponse createTokenInfo(Long userId) { - return jwtService.createTokenInfo(userId); + List tokens = jwtUtils.createTokenInfo(userId); + return TokenResponse.of(tokens.get(0), tokens.get(1)); } @Transactional public RefreshResponse reissueToken(TokenRequestDto request) { - Long userId = jwtService.getUserIdFromJwt(request.getAccessToken()); + Long userId = jwtUtils.getUserIdFromJwt(request.getAccessToken()); User user = UserServiceUtils.findUserById(userRepository, userId); - if (!jwtService.validateToken(request.getRefreshToken())) { + if (!jwtUtils.validateToken(request.getRefreshToken())) { user.resetFcmToken(); throw new UnAuthorizedException(String.format("주어진 리프레시 토큰 (%s) 이 유효하지 않습니다.", request.getRefreshToken())); } @@ -48,12 +50,13 @@ public RefreshResponse reissueToken(TokenRequestDto request) { throw new UnAuthorizedException(String.format("이미 만료된 리프레시 토큰 (%s) 입니다.", request.getRefreshToken())); } if (!refreshToken.equals(request.getRefreshToken())) { - jwtService.expireRefreshToken(user.getId()); + jwtUtils.expireRefreshToken(user.getId()); user.resetFcmToken(); throw new UnAuthorizedException( String.format("해당 리프레시 토큰 (%s) 의 정보가 일치하지 않습니다.", request.getRefreshToken())); } - TokenResponse token = jwtService.createTokenInfo(userId); + List tokens = jwtUtils.createTokenInfo(userId); + TokenResponse token = TokenResponse.of(tokens.get(0), tokens.get(1)); boolean isJoiningRoom = roomService.existsParticipatingRoomByUserId(userId); return RefreshResponse.of(token, isJoiningRoom); } diff --git a/hous-api/src/main/java/hous/api/service/auth/impl/AppleAuthService.java b/hous-api/src/main/java/hous/api/service/auth/impl/AppleAuthService.java index 6a45f003..3f2d308c 100644 --- a/hous-api/src/main/java/hous/api/service/auth/impl/AppleAuthService.java +++ b/hous-api/src/main/java/hous/api/service/auth/impl/AppleAuthService.java @@ -10,9 +10,9 @@ import hous.api.service.auth.CommonAuthServiceUtils; import hous.api.service.auth.dto.request.LoginDto; import hous.api.service.auth.dto.request.SignUpDto; -import hous.api.service.jwt.JwtService; import hous.api.service.user.UserService; import hous.api.service.user.UserServiceUtils; +import hous.common.util.JwtUtils; import hous.core.domain.user.User; import hous.core.domain.user.UserSocialType; import hous.core.domain.user.mysql.UserRepository; @@ -34,7 +34,7 @@ public class AppleAuthService implements AuthService { private final CommonAuthService commonAuthService; - private final JwtService jwtService; + private final JwtUtils jwtUtils; private final RedisTemplate redisTemplate; @@ -60,7 +60,7 @@ public Long forceLogin(LoginDto request) { String socialId = appleTokenDecoder.getSocialIdFromIdToken(request.getToken()); User user = UserServiceUtils.findUserBySocialIdAndSocialType(userRepository, socialId, socialType); commonAuthService.resetConflictFcmToken(request.getFcmToken()); - CommonAuthServiceUtils.forceLogoutUser(redisTemplate, jwtService, user); + CommonAuthServiceUtils.forceLogoutUser(redisTemplate, jwtUtils, user); user.updateFcmToken(request.getFcmToken()); return user.getId(); } diff --git a/hous-api/src/main/java/hous/api/service/auth/impl/KakaoAuthService.java b/hous-api/src/main/java/hous/api/service/auth/impl/KakaoAuthService.java index a7738dde..3bfbafe0 100644 --- a/hous-api/src/main/java/hous/api/service/auth/impl/KakaoAuthService.java +++ b/hous-api/src/main/java/hous/api/service/auth/impl/KakaoAuthService.java @@ -10,10 +10,10 @@ import hous.api.service.auth.CommonAuthServiceUtils; import hous.api.service.auth.dto.request.LoginDto; import hous.api.service.auth.dto.request.SignUpDto; -import hous.api.service.jwt.JwtService; import hous.api.service.user.UserService; import hous.api.service.user.UserServiceUtils; import hous.common.util.HttpHeaderUtils; +import hous.common.util.JwtUtils; import hous.core.domain.user.User; import hous.core.domain.user.UserSocialType; import hous.core.domain.user.mysql.UserRepository; @@ -36,7 +36,7 @@ public class KakaoAuthService implements AuthService { private final CommonAuthService commonAuthService; - private final JwtService jwtService; + private final JwtUtils jwtUtils; private final RedisTemplate redisTemplate; @@ -65,7 +65,7 @@ public Long forceLogin(LoginDto request) { HttpHeaderUtils.withBearerToken(request.getToken())); User user = UserServiceUtils.findUserBySocialIdAndSocialType(userRepository, response.getId(), socialType); commonAuthService.resetConflictFcmToken(request.getFcmToken()); - CommonAuthServiceUtils.forceLogoutUser(redisTemplate, jwtService, user); + CommonAuthServiceUtils.forceLogoutUser(redisTemplate, jwtUtils, user); user.updateFcmToken(request.getFcmToken()); return user.getId(); } diff --git a/hous-api/src/main/java/hous/api/service/user/UserService.java b/hous-api/src/main/java/hous/api/service/user/UserService.java index 256aaad2..3f62b701 100644 --- a/hous-api/src/main/java/hous/api/service/user/UserService.java +++ b/hous-api/src/main/java/hous/api/service/user/UserService.java @@ -7,7 +7,6 @@ import hous.api.service.badge.BadgeService; import hous.api.service.badge.BadgeServiceUtils; -import hous.api.service.jwt.JwtService; import hous.api.service.room.RoomServiceUtils; import hous.api.service.todo.TodoServiceUtils; import hous.api.service.user.dto.request.CreateUserRequestDto; @@ -16,6 +15,7 @@ import hous.api.service.user.dto.request.UpdateTestScoreRequestDto; import hous.api.service.user.dto.request.UpdateUserInfoRequestDto; import hous.api.service.user.dto.response.UpdatePersonalityColorResponse; +import hous.common.util.JwtUtils; import hous.core.domain.badge.Badge; import hous.core.domain.badge.BadgeCounter; import hous.core.domain.badge.BadgeCounterType; @@ -70,7 +70,7 @@ public class UserService { private final BadgeCounterRepository badgeCounterRepository; private final BadgeService badgeService; - private final JwtService jwtService; + private final JwtUtils jwtUtils; public Long registerUser(CreateUserRequestDto request) { UserServiceUtils.validateNotExistsUser(userRepository, request.getSocialId(), request.getSocialType()); @@ -86,7 +86,7 @@ public Long registerUser(CreateUserRequestDto request) { request.getIsPublic())); User conflictFcmTokenUser = userRepository.findUserByFcmToken(request.getFcmToken()); if (conflictFcmTokenUser != null) { - jwtService.expireRefreshToken(conflictFcmTokenUser.getId()); + jwtUtils.expireRefreshToken(conflictFcmTokenUser.getId()); conflictFcmTokenUser.resetFcmToken(); } user.updateFcmToken(request.getFcmToken()); diff --git a/hous-common/build.gradle b/hous-common/build.gradle index 86b892b6..3ecf53a9 100644 --- a/hous-common/build.gradle +++ b/hous-common/build.gradle @@ -4,4 +4,9 @@ jar { enabled = true } dependencies { implementation "org.springframework.boot:spring-boot-starter-web" implementation "org.springframework.cloud:spring-cloud-starter-openfeign" + implementation group: "io.jsonwebtoken", name: "jjwt-api", version: "0.11.2" + implementation group: "io.jsonwebtoken", name: "jjwt-impl", version: "0.11.2" + implementation group: "io.jsonwebtoken", name: "jjwt-jackson", version: "0.11.2" + implementation "org.springframework.boot:spring-boot-starter-data-redis" + implementation "org.springframework.session:spring-session-data-redis" } diff --git a/hous-api/src/main/java/hous/api/config/security/JwtConstants.java b/hous-common/src/main/java/hous/common/constant/JwtKeys.java similarity index 69% rename from hous-api/src/main/java/hous/api/config/security/JwtConstants.java rename to hous-common/src/main/java/hous/common/constant/JwtKeys.java index 38ba9d25..567ebf1d 100644 --- a/hous-api/src/main/java/hous/api/config/security/JwtConstants.java +++ b/hous-common/src/main/java/hous/common/constant/JwtKeys.java @@ -1,10 +1,10 @@ -package hous.api.config.security; +package hous.common.constant; import lombok.AccessLevel; import lombok.NoArgsConstructor; @NoArgsConstructor(access = AccessLevel.PRIVATE) -public abstract class JwtConstants { +public final class JwtKeys { public static final String USER_ID = "USER_ID"; } diff --git a/hous-api/src/main/java/hous/api/service/jwt/JwtService.java b/hous-common/src/main/java/hous/common/util/JwtUtils.java similarity index 86% rename from hous-api/src/main/java/hous/api/service/jwt/JwtService.java rename to hous-common/src/main/java/hous/common/util/JwtUtils.java index 727824a5..01b31d6d 100644 --- a/hous-api/src/main/java/hous/api/service/jwt/JwtService.java +++ b/hous-common/src/main/java/hous/common/util/JwtUtils.java @@ -1,15 +1,15 @@ -package hous.api.service.jwt; +package hous.common.util; import java.security.Key; import java.util.Date; +import java.util.List; import java.util.concurrent.TimeUnit; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; -import hous.api.config.security.JwtConstants; -import hous.api.service.auth.dto.response.TokenResponse; +import hous.common.constant.JwtKeys; import hous.common.constant.RedisKey; import io.jsonwebtoken.Claims; import io.jsonwebtoken.ExpiredJwtException; @@ -24,7 +24,7 @@ @Component @Slf4j -public class JwtService { +public class JwtUtils { private final RedisTemplate redisTemplate; @@ -36,13 +36,13 @@ public class JwtService { private final Key secretKey; - public JwtService(@Value("${jwt.secret}") String secretKey, RedisTemplate redisTemplate) { + public JwtUtils(@Value("${jwt.secret}") String secretKey, RedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; byte[] keyBytes = Decoders.BASE64.decode(secretKey); this.secretKey = Keys.hmacShaKeyFor(keyBytes); } - public TokenResponse createTokenInfo(Long userId) { + public List createTokenInfo(Long userId) { long now = (new Date()).getTime(); Date accessTokenExpiresIn = new Date(now + ACCESS_TOKEN_EXPIRE_TIME); @@ -50,7 +50,7 @@ public TokenResponse createTokenInfo(Long userId) { // Access Token 생성 String accessToken = Jwts.builder() - .claim(JwtConstants.USER_ID, userId) + .claim(JwtKeys.USER_ID, userId) .setExpiration(accessTokenExpiresIn) .signWith(secretKey, SignatureAlgorithm.HS512) .compact(); @@ -64,7 +64,7 @@ public TokenResponse createTokenInfo(Long userId) { redisTemplate.opsForValue() .set(RedisKey.REFRESH_TOKEN + userId, refreshToken, REFRESH_TOKEN_EXPIRE_TIME, TimeUnit.MILLISECONDS); - return TokenResponse.of(accessToken, refreshToken); + return List.of(accessToken, refreshToken); } public void expireRefreshToken(Long userId) { @@ -90,7 +90,7 @@ public boolean validateToken(String token) { } public Long getUserIdFromJwt(String accessToken) { - return parseClaims(accessToken).get(JwtConstants.USER_ID, Long.class); + return parseClaims(accessToken).get(JwtKeys.USER_ID, Long.class); } private Claims parseClaims(String accessToken) {