diff --git a/src/main/java/com/stempo/api/domain/application/service/LoginServiceImpl.java b/src/main/java/com/stempo/api/domain/application/service/LoginServiceImpl.java index e7410b41..04066d24 100644 --- a/src/main/java/com/stempo/api/domain/application/service/LoginServiceImpl.java +++ b/src/main/java/com/stempo/api/domain/application/service/LoginServiceImpl.java @@ -1,6 +1,5 @@ package com.stempo.api.domain.application.service; -import com.stempo.api.domain.domain.model.RedisToken; import com.stempo.api.domain.domain.model.User; import com.stempo.api.domain.presentation.dto.response.TokenInfo; import com.stempo.api.global.auth.exception.TokenForgeryException; @@ -15,39 +14,41 @@ public class LoginServiceImpl implements LoginService { private final UserService userService; - private final RedisTokenService redisTokenService; private final JwtTokenProvider jwtTokenProvider; @Override public TokenInfo loginOrRegister(String deviceTag, String password) { User user = userService.findById(deviceTag) .orElseGet(() -> userService.registerUser(deviceTag, password)); - return generateAndSaveToken(user); + return generateToken(user); } @Override public TokenInfo reissueToken(HttpServletRequest request) { String refreshToken = jwtTokenProvider.resolveToken(request); - Authentication authentication = jwtTokenProvider.getAuthentication(refreshToken); - RedisToken redisToken = redisTokenService.findByRefreshToken(refreshToken); + validateRefreshToken(refreshToken); + return reissueToken(refreshToken); + } - validateUserExistence(authentication); + private TokenInfo generateToken(User loginUser) { + return jwtTokenProvider.generateToken(loginUser.getDeviceTag(), loginUser.getRole()); + } - TokenInfo newTokenInfo = jwtTokenProvider.generateToken(redisToken.getId(), redisToken.getRole()); - redisTokenService.saveToken(redisToken.getId(), redisToken.getRole(), newTokenInfo); - return newTokenInfo; + private void validateRefreshToken(String refreshToken) { + if (!jwtTokenProvider.isRefreshToken(refreshToken)) { + throw new TokenForgeryException("Invalid refresh token."); + } } - private TokenInfo generateAndSaveToken(User loginUser) { - TokenInfo tokenInfo = jwtTokenProvider.generateToken(loginUser.getDeviceTag(), loginUser.getRole()); - redisTokenService.saveToken(loginUser.getDeviceTag(), loginUser.getRole(), tokenInfo); - return tokenInfo; + private TokenInfo reissueToken(String refreshToken) { + Authentication authentication = jwtTokenProvider.getAuthentication(refreshToken); + User user = getTokenUserInfo(authentication); + return jwtTokenProvider.generateToken(user.getDeviceTag(), user.getRole()); } - private void validateUserExistence(Authentication authentication) { + private User getTokenUserInfo(Authentication authentication) { String id = authentication.getName(); - if (!userService.existsById(id)) { - throw new TokenForgeryException("Non-existent user token."); - } + return userService.findById(id) + .orElseThrow(() -> new TokenForgeryException("Non-existent user token.")); } } diff --git a/src/main/java/com/stempo/api/domain/application/service/RedisTokenService.java b/src/main/java/com/stempo/api/domain/application/service/RedisTokenService.java deleted file mode 100644 index 4f4bc045..00000000 --- a/src/main/java/com/stempo/api/domain/application/service/RedisTokenService.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.stempo.api.domain.application.service; - -import com.stempo.api.domain.domain.model.RedisToken; -import com.stempo.api.domain.domain.model.Role; -import com.stempo.api.domain.presentation.dto.response.TokenInfo; - -public interface RedisTokenService { - - RedisToken findByAccessToken(String token); - - RedisToken findByRefreshToken(String token); - - void saveToken(String id, Role role, TokenInfo tokenInfo); -} diff --git a/src/main/java/com/stempo/api/domain/application/service/RedisTokenServiceImpl.java b/src/main/java/com/stempo/api/domain/application/service/RedisTokenServiceImpl.java deleted file mode 100644 index a327f1d8..00000000 --- a/src/main/java/com/stempo/api/domain/application/service/RedisTokenServiceImpl.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.stempo.api.domain.application.service; - -import com.stempo.api.domain.domain.model.RedisToken; -import com.stempo.api.domain.domain.model.Role; -import com.stempo.api.domain.domain.repository.RedisTokenRepository; -import com.stempo.api.domain.presentation.dto.response.TokenInfo; -import com.stempo.api.global.auth.exception.TokenNotFoundException; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - -@Service -@RequiredArgsConstructor -public class RedisTokenServiceImpl implements RedisTokenService { - - private final RedisTokenRepository redisTokenRepository; - - @Override - public RedisToken findByAccessToken(String token) { - return redisTokenRepository.findByAccessToken(token) - .orElseThrow(() -> new TokenNotFoundException("존재하지 않는 토큰입니다.")); - } - - @Override - public RedisToken findByRefreshToken(String token) { - return redisTokenRepository.findByRefreshToken(token) - .orElseThrow(() -> new TokenNotFoundException("존재하지 않는 토큰입니다.")); - } - - @Override - public void saveToken(String id, Role role, TokenInfo tokenInfo) { - RedisToken redisToken = RedisToken.create(id, role, tokenInfo); - redisTokenRepository.save(redisToken); - } -} diff --git a/src/main/java/com/stempo/api/domain/domain/model/RedisToken.java b/src/main/java/com/stempo/api/domain/domain/model/RedisToken.java deleted file mode 100644 index 02a0ac07..00000000 --- a/src/main/java/com/stempo/api/domain/domain/model/RedisToken.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.stempo.api.domain.domain.model; - -import com.stempo.api.domain.presentation.dto.response.TokenInfo; -import jakarta.persistence.Column; -import jakarta.persistence.Id; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import org.springframework.data.redis.core.RedisHash; -import org.springframework.data.redis.core.index.Indexed; - -@Getter -@Setter -@Builder -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@AllArgsConstructor(access = AccessLevel.PRIVATE) -@RedisHash(value = "refresh", timeToLive = 60 * 60 * 24 * 14) -public class RedisToken { - - @Id - @Column(name = "user_id") - private String id; - - private Role role; - - @Indexed - private String accessToken; - - @Indexed - private String refreshToken; - - public static RedisToken create(String id, Role role, TokenInfo tokenInfo) { - return RedisToken.builder() - .id(id) - .role(role) - .accessToken(tokenInfo.getAccessToken()) - .refreshToken(tokenInfo.getRefreshToken()) - .build(); - } -} diff --git a/src/main/java/com/stempo/api/domain/domain/repository/RedisTokenRepository.java b/src/main/java/com/stempo/api/domain/domain/repository/RedisTokenRepository.java deleted file mode 100644 index f3442e68..00000000 --- a/src/main/java/com/stempo/api/domain/domain/repository/RedisTokenRepository.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.stempo.api.domain.domain.repository; - -import com.stempo.api.domain.domain.model.RedisToken; - -import java.util.Optional; - -public interface RedisTokenRepository { - - Optional findByAccessToken(String token); - - Optional findByRefreshToken(String token); - - void save(RedisToken redisToken); -} diff --git a/src/main/java/com/stempo/api/domain/persistence/repository/RedisTokenJpaRepository.java b/src/main/java/com/stempo/api/domain/persistence/repository/RedisTokenJpaRepository.java deleted file mode 100644 index aeb8b02a..00000000 --- a/src/main/java/com/stempo/api/domain/persistence/repository/RedisTokenJpaRepository.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.stempo.api.domain.persistence.repository; - -import com.stempo.api.domain.domain.model.RedisToken; -import org.springframework.data.repository.CrudRepository; - -import java.util.Optional; - -public interface RedisTokenJpaRepository extends CrudRepository { - - Optional findByAccessToken(String token); - - Optional findByRefreshToken(String token); -} diff --git a/src/main/java/com/stempo/api/domain/persistence/repository/RedisTokenRepositoryImpl.java b/src/main/java/com/stempo/api/domain/persistence/repository/RedisTokenRepositoryImpl.java deleted file mode 100644 index 9815ce39..00000000 --- a/src/main/java/com/stempo/api/domain/persistence/repository/RedisTokenRepositoryImpl.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.stempo.api.domain.persistence.repository; - -import com.stempo.api.domain.domain.model.RedisToken; -import com.stempo.api.domain.domain.repository.RedisTokenRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Repository; - -import java.util.Optional; - -@Repository -@RequiredArgsConstructor -public class RedisTokenRepositoryImpl implements RedisTokenRepository { - - private final RedisTokenJpaRepository repository; - - @Override - public Optional findByAccessToken(String token) { - return repository.findByAccessToken(token); - } - - @Override - public Optional findByRefreshToken(String token) { - return repository.findByRefreshToken(token); - } - - @Override - public void save(RedisToken redisToken) { - repository.save(redisToken); - } -} diff --git a/src/main/java/com/stempo/api/global/auth/filter/JwtAuthenticationFilter.java b/src/main/java/com/stempo/api/global/auth/filter/JwtAuthenticationFilter.java index 345b19df..570f8a72 100644 --- a/src/main/java/com/stempo/api/global/auth/filter/JwtAuthenticationFilter.java +++ b/src/main/java/com/stempo/api/global/auth/filter/JwtAuthenticationFilter.java @@ -1,15 +1,11 @@ package com.stempo.api.global.auth.filter; -import com.stempo.api.domain.application.service.RedisTokenService; -import com.stempo.api.domain.domain.model.RedisToken; import com.stempo.api.global.auth.jwt.JwtTokenProvider; -import com.stempo.api.global.util.ResponseUtil; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletResponse; import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.security.core.Authentication; @@ -17,33 +13,26 @@ import org.springframework.web.filter.GenericFilterBean; import java.io.IOException; +import java.util.Objects; @RequiredArgsConstructor @Slf4j public class JwtAuthenticationFilter extends GenericFilterBean { - private final RedisTokenService redisTokenService; private final JwtTokenProvider jwtTokenProvider; @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpServletRequest = (HttpServletRequest) request; - HttpServletResponse httpServletResponse = (HttpServletResponse) response; - if (!authenticateToken(httpServletRequest, httpServletResponse)) { + if (!authenticateToken(httpServletRequest)) { return; } chain.doFilter(request, response); } - private boolean authenticateToken(HttpServletRequest request, HttpServletResponse response) throws IOException { + private boolean authenticateToken(HttpServletRequest request) throws IOException { String token = jwtTokenProvider.resolveToken(request); - if (token != null && jwtTokenProvider.validateToken(token)) { - RedisToken redisToken = jwtTokenProvider.isRefreshToken(token) ? redisTokenService.findByRefreshToken(token) : redisTokenService.findByAccessToken(token); - if (redisToken == null) { - log.warn("Token not found in redis"); - ResponseUtil.sendErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED); - return false; - } + if (Objects.nonNull(token) && jwtTokenProvider.validateTokenSilently(token)) { Authentication authentication = jwtTokenProvider.getAuthentication(token); SecurityContextHolder.getContext().setAuthentication(authentication); } diff --git a/src/main/java/com/stempo/api/global/auth/jwt/JwtTokenProvider.java b/src/main/java/com/stempo/api/global/auth/jwt/JwtTokenProvider.java index 4a3af905..e2e97e84 100644 --- a/src/main/java/com/stempo/api/global/auth/jwt/JwtTokenProvider.java +++ b/src/main/java/com/stempo/api/global/auth/jwt/JwtTokenProvider.java @@ -129,6 +129,18 @@ public boolean validateToken(String token) { return false; } + public boolean validateTokenSilently(String token) { + try { + Jwts.parser() + .setSigningKey(key) + .build() + .parseClaimsJws(token); + return true; + } catch (Exception e) { + return false; + } + } + public Claims parseClaims(String accessToken) { try { return Jwts.parser() diff --git a/src/main/java/com/stempo/api/global/config/SecurityConfig.java b/src/main/java/com/stempo/api/global/config/SecurityConfig.java index 5fea41ec..eae8db54 100644 --- a/src/main/java/com/stempo/api/global/config/SecurityConfig.java +++ b/src/main/java/com/stempo/api/global/config/SecurityConfig.java @@ -1,6 +1,5 @@ package com.stempo.api.global.config; -import com.stempo.api.domain.application.service.RedisTokenService; import com.stempo.api.global.auth.filter.JwtAuthenticationFilter; import com.stempo.api.global.auth.jwt.JwtTokenProvider; import lombok.RequiredArgsConstructor; @@ -20,7 +19,6 @@ @EnableGlobalMethodSecurity(securedEnabled = true) public class SecurityConfig { - private final RedisTokenService redisTokenService; private final JwtTokenProvider jwtTokenProvider; @Bean @@ -34,7 +32,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { authorizeRequests.anyRequest().permitAll() ) .addFilterBefore( - new JwtAuthenticationFilter(redisTokenService, jwtTokenProvider), + new JwtAuthenticationFilter(jwtTokenProvider), UsernamePasswordAuthenticationFilter.class ); return http.build();