From 6b6716d9bcd2a5f413504ee66e4c295b2ba370fe Mon Sep 17 00:00:00 2001 From: Yu-jimin Date: Mon, 12 Feb 2024 23:36:52 +0900 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20docker=EC=97=90=20redis=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20(#40)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 7 +++++++ src/main/resources/application.yml | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 4c9d5e1..2439545 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,13 @@ version: '3' services: + redis: + image: redis + container_name: redis + ports: + - 6379:6379 + restart: always + web: container_name: web image: ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_REPO }} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 1dcd6bf..53c693e 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,4 +1,8 @@ spring: + data: + redis: + host: redis + port: 6379 datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: ${SPRING_DATABASE_URL} From 5aceff0da3e5737639e1e01d6f546e3ee6f21ca7 Mon Sep 17 00:00:00 2001 From: Yu-jimin Date: Wed, 14 Feb 2024 02:34:28 +0900 Subject: [PATCH 2/6] =?UTF-8?q?feat:=20JwtAuthFilter,=20SecurityConfig?= =?UTF-8?q?=EC=97=90=20redis=20=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80=20(?= =?UTF-8?q?#40)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/controller/UserController.java | 6 +++- .../domain/user/service/RedisService.java | 30 +++++++++++++++++ .../once/domain/user/service/UserService.java | 1 + .../once/global/config/JwtSecurityConfig.java | 21 ++++++++++++ .../lux/once/global/config/RedisConfig.java | 33 +++++++++++++++++++ .../once/global/config/SecurityConfig.java | 5 +-- .../once/global/security/JwtAuthFilter.java | 26 ++++++++------- 7 files changed, 108 insertions(+), 14 deletions(-) create mode 100644 src/main/java/ewha/lux/once/domain/user/service/RedisService.java create mode 100644 src/main/java/ewha/lux/once/global/config/JwtSecurityConfig.java create mode 100644 src/main/java/ewha/lux/once/global/config/RedisConfig.java diff --git a/src/main/java/ewha/lux/once/domain/user/controller/UserController.java b/src/main/java/ewha/lux/once/domain/user/controller/UserController.java index 1f78194..fe3ec96 100644 --- a/src/main/java/ewha/lux/once/domain/user/controller/UserController.java +++ b/src/main/java/ewha/lux/once/domain/user/controller/UserController.java @@ -2,6 +2,7 @@ import ewha.lux.once.domain.user.dto.*; import ewha.lux.once.domain.user.entity.Users; +import ewha.lux.once.domain.user.service.RedisService; import ewha.lux.once.domain.user.service.UserService; import ewha.lux.once.global.common.CommonResponse; import ewha.lux.once.global.common.CustomException; @@ -18,6 +19,7 @@ import java.io.IOException; import java.text.ParseException; +import java.util.concurrent.TimeUnit; @Controller @RestController @@ -27,6 +29,7 @@ public class UserController { private final UserService userService; private final JwtProvider jwtProvider; + private final RedisService redisService; // [Post] 회원가입 @PostMapping("/signup") @@ -38,6 +41,7 @@ public CommonResponse signup(@RequestBody SignupRequestDto request) throws Pa String refreshToken = jwtProvider.generateRefreshToken(users.getLoginId()); LoginResponseDto loginResponseDto = new LoginResponseDto(users.getId(), accessToken, refreshToken); + redisService.setValueWithTTL(refreshToken, users.getId().toString(), 14L, TimeUnit.DAYS); return new CommonResponse<>(ResponseCode.SUCCESS, loginResponseDto); } catch (CustomException e) { return new CommonResponse<>(e.getStatus()); @@ -54,7 +58,7 @@ public CommonResponse signin(@RequestBody SignInRequestDto request) { String refreshToken = jwtProvider.generateRefreshToken(user.getLoginId()); LoginResponseDto loginResponseDto = new LoginResponseDto(user.getId(), accessToken, refreshToken); - + redisService.setValueWithTTL(refreshToken, user.getId().toString(), 14L, TimeUnit.DAYS); return new CommonResponse<>(ResponseCode.SUCCESS, loginResponseDto); } catch (CustomException e) { return new CommonResponse<>(e.getStatus()); diff --git a/src/main/java/ewha/lux/once/domain/user/service/RedisService.java b/src/main/java/ewha/lux/once/domain/user/service/RedisService.java new file mode 100644 index 0000000..c5b3232 --- /dev/null +++ b/src/main/java/ewha/lux/once/domain/user/service/RedisService.java @@ -0,0 +1,30 @@ +package ewha.lux.once.domain.user.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.stereotype.Service; + +import java.util.concurrent.TimeUnit; + +@Service +@RequiredArgsConstructor +public class RedisService { + private final RedisTemplate redisTemplate; + + public void setValueWithTTL(String key, Object value, long timeout, TimeUnit unit) { + ValueOperations valueOperations = redisTemplate.opsForValue(); + valueOperations.set(key, value, timeout, unit); + } + + public Object getValue(String key) { + ValueOperations valueOperations = redisTemplate.opsForValue(); + Object object = valueOperations.get(key); + return object; + } + + public void deleteValue(String key) { + redisTemplate.delete(key); + } +} diff --git a/src/main/java/ewha/lux/once/domain/user/service/UserService.java b/src/main/java/ewha/lux/once/domain/user/service/UserService.java index 49f32a4..0be16c9 100644 --- a/src/main/java/ewha/lux/once/domain/user/service/UserService.java +++ b/src/main/java/ewha/lux/once/domain/user/service/UserService.java @@ -12,6 +12,7 @@ import ewha.lux.once.global.repository.OwnedCardRepository; import ewha.lux.once.global.repository.UsersRepository; import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; diff --git a/src/main/java/ewha/lux/once/global/config/JwtSecurityConfig.java b/src/main/java/ewha/lux/once/global/config/JwtSecurityConfig.java new file mode 100644 index 0000000..6d8b823 --- /dev/null +++ b/src/main/java/ewha/lux/once/global/config/JwtSecurityConfig.java @@ -0,0 +1,21 @@ +package ewha.lux.once.global.config; + +import ewha.lux.once.domain.user.service.RedisService; +import ewha.lux.once.global.security.JwtAuthFilter; +import ewha.lux.once.global.security.JwtProvider; +import lombok.RequiredArgsConstructor; +import org.springframework.security.config.annotation.SecurityConfigurerAdapter; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.web.DefaultSecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +@RequiredArgsConstructor +public class JwtSecurityConfig extends SecurityConfigurerAdapter { + private final JwtProvider jwtProvider; + private final RedisService redisService; + + @Override + public void configure(HttpSecurity http) throws Exception{ + http.addFilterBefore(new JwtAuthFilter(jwtProvider, redisService), UsernamePasswordAuthenticationFilter.class); + } +} diff --git a/src/main/java/ewha/lux/once/global/config/RedisConfig.java b/src/main/java/ewha/lux/once/global/config/RedisConfig.java new file mode 100644 index 0000000..f8f86b0 --- /dev/null +++ b/src/main/java/ewha/lux/once/global/config/RedisConfig.java @@ -0,0 +1,33 @@ +package ewha.lux.once.global.config; + +import lombok.RequiredArgsConstructor; +import org.springframework.boot.autoconfigure.data.redis.RedisProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.repository.configuration.EnableRedisRepositories; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +@RequiredArgsConstructor +@Configuration +@EnableRedisRepositories +public class RedisConfig { + private final RedisProperties redisProperties; + + @Bean + public RedisConnectionFactory redisConnectionFactory() { + return new LettuceConnectionFactory(redisProperties.getHost(), redisProperties.getPort()); + } + + @Bean + public RedisTemplate redisTemplate() { + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(redisConnectionFactory()); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(new StringRedisSerializer()); + return redisTemplate; + } + +} diff --git a/src/main/java/ewha/lux/once/global/config/SecurityConfig.java b/src/main/java/ewha/lux/once/global/config/SecurityConfig.java index fd29dba..157d7a7 100644 --- a/src/main/java/ewha/lux/once/global/config/SecurityConfig.java +++ b/src/main/java/ewha/lux/once/global/config/SecurityConfig.java @@ -1,5 +1,6 @@ package ewha.lux.once.global.config; +import ewha.lux.once.domain.user.service.RedisService; import ewha.lux.once.global.security.JwtAuthFilter; import ewha.lux.once.global.security.JwtProvider; import lombok.RequiredArgsConstructor; @@ -25,7 +26,7 @@ @Configuration public class SecurityConfig { private final JwtProvider jwtProvider; - + private final RedisService redisService; @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { @@ -60,7 +61,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .requestMatchers("/user/card/search").permitAll() .anyRequest().authenticated() ) - .addFilterBefore(new JwtAuthFilter(jwtProvider), UsernamePasswordAuthenticationFilter.class); + .addFilterBefore(new JwtAuthFilter(jwtProvider, redisService), UsernamePasswordAuthenticationFilter.class); return http.build(); diff --git a/src/main/java/ewha/lux/once/global/security/JwtAuthFilter.java b/src/main/java/ewha/lux/once/global/security/JwtAuthFilter.java index 7b27331..6d7441d 100644 --- a/src/main/java/ewha/lux/once/global/security/JwtAuthFilter.java +++ b/src/main/java/ewha/lux/once/global/security/JwtAuthFilter.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import ewha.lux.once.domain.user.dto.LoginResponseDto; +import ewha.lux.once.domain.user.service.RedisService; +import ewha.lux.once.global.common.CustomException; import ewha.lux.once.global.common.UserAccount; import ewha.lux.once.domain.user.entity.Users; import ewha.lux.once.global.common.ResponseDto; @@ -28,6 +30,7 @@ @RequiredArgsConstructor public class JwtAuthFilter extends OncePerRequestFilter { private final JwtProvider jwtProvider; + private final RedisService redisService; public static final String HEADER_KEY = "Authorization"; public static final String REFRESH_HEADER_KEY = "Authorization-refresh"; public static final String PREFIX = "Bearer "; @@ -37,12 +40,19 @@ public class JwtAuthFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + String accessToken = resolveToken(request, HEADER_KEY); + String refreshToken = resolveToken(request, REFRESH_HEADER_KEY); + // 자동 로그인 요청인 경우 if(request.getRequestURI().equals("/user/auto")) { - - String accessToken = resolveToken(request, HEADER_KEY); - String refreshToken = resolveToken(request, REFRESH_HEADER_KEY); - + if ("Deprecated".equals(redisService.getValue(refreshToken))) { + response.setContentType("application/json"); + response.setCharacterEncoding("utf-8"); + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + response.getWriter().write(new ObjectMapper().writeValueAsString(ResponseEntity.ok(ResponseDto.response(1000, true, "refresh token이 만료되었습니다. 다시 로그인해주세요")))); + return; + } + // 토큰 유효성 검사 if (!jwtProvider.validateAccessTokenExpiration(accessToken)) { // accesstoken이 유효한 경우 Users users = jwtProvider.validateTokenAndGetUsers(accessToken); LoginResponseDto loginResponseDto = new LoginResponseDto(users.getId(), accessToken, refreshToken); @@ -50,7 +60,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response.setContentType("application/json"); response.setCharacterEncoding("utf-8"); response.setStatus(HttpServletResponse.SC_OK); - response.getWriter().write(new ObjectMapper().writeValueAsString(ResponseEntity.ok(ResponseDto.response(1000,true, "access token이 검증되었습니다.", loginResponseDto)))); + response.getWriter().write(new ObjectMapper().writeValueAsString(ResponseEntity.ok(ResponseDto.response(1000, true, "access token이 검증되었습니다.", loginResponseDto)))); return; } else if (!jwtProvider.validateAccessTokenExpiration(refreshToken)) { // accesstoken 만료, refreshtoken이 유효한 경우 Users users = jwtProvider.validateTokenAndGetUsers(refreshToken); @@ -70,9 +80,6 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse return; } } - - String accessToken = resolveToken(request, HEADER_KEY); - if(StringUtils.hasText(accessToken) && jwtProvider.validateToken(accessToken)){ Users users = jwtProvider.validateTokenAndGetUsers(accessToken); @@ -80,9 +87,6 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse filterChain.doFilter(request, response); return; } - - - filterChain.doFilter(request, response); } public void saveAuthentication(Users users) { From 362601afa42b3de7b761c3fd8edc6da3715385b7 Mon Sep 17 00:00:00 2001 From: Yu-jimin Date: Thu, 15 Feb 2024 01:23:46 +0900 Subject: [PATCH 3/6] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=95=84?= =?UTF-8?q?=EC=9B=83=20=EA=B5=AC=ED=98=84=20=EB=B0=8F=20=ED=9A=8C=EC=9B=90?= =?UTF-8?q?=EA=B0=80=EC=9E=85,=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EB=B3=80=EA=B2=BD=20(#40)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/controller/UserController.java | 34 +++++++----------- .../once/domain/user/service/UserService.java | 35 ++++++++++++++++--- .../lux/once/global/security/JwtProvider.java | 18 +++++++++- 3 files changed, 61 insertions(+), 26 deletions(-) diff --git a/src/main/java/ewha/lux/once/domain/user/controller/UserController.java b/src/main/java/ewha/lux/once/domain/user/controller/UserController.java index fe3ec96..61a68a6 100644 --- a/src/main/java/ewha/lux/once/domain/user/controller/UserController.java +++ b/src/main/java/ewha/lux/once/domain/user/controller/UserController.java @@ -1,14 +1,12 @@ package ewha.lux.once.domain.user.controller; import ewha.lux.once.domain.user.dto.*; -import ewha.lux.once.domain.user.entity.Users; -import ewha.lux.once.domain.user.service.RedisService; import ewha.lux.once.domain.user.service.UserService; import ewha.lux.once.global.common.CommonResponse; import ewha.lux.once.global.common.CustomException; import ewha.lux.once.global.common.ResponseCode; import ewha.lux.once.global.common.UserAccount; -import ewha.lux.once.global.security.JwtProvider; +import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import org.springframework.data.repository.query.Param; import org.springframework.http.MediaType; @@ -19,7 +17,6 @@ import java.io.IOException; import java.text.ParseException; -import java.util.concurrent.TimeUnit; @Controller @RestController @@ -28,21 +25,12 @@ public class UserController { private final UserService userService; - private final JwtProvider jwtProvider; - private final RedisService redisService; // [Post] 회원가입 @PostMapping("/signup") public CommonResponse signup(@RequestBody SignupRequestDto request) throws ParseException { try { - Users users = userService.signup(request); - - String accessToken = jwtProvider.generateAccessToken(users.getLoginId()); - String refreshToken = jwtProvider.generateRefreshToken(users.getLoginId()); - - LoginResponseDto loginResponseDto = new LoginResponseDto(users.getId(), accessToken, refreshToken); - redisService.setValueWithTTL(refreshToken, users.getId().toString(), 14L, TimeUnit.DAYS); - return new CommonResponse<>(ResponseCode.SUCCESS, loginResponseDto); + return new CommonResponse<>(ResponseCode.SUCCESS, userService.signup(request)); } catch (CustomException e) { return new CommonResponse<>(e.getStatus()); } @@ -52,14 +40,18 @@ public CommonResponse signup(@RequestBody SignupRequestDto request) throws Pa @PostMapping("/login") public CommonResponse signin(@RequestBody SignInRequestDto request) { try { - Users user = userService.authenticate(request); - - String accessToken = jwtProvider.generateAccessToken(user.getLoginId()); - String refreshToken = jwtProvider.generateRefreshToken(user.getLoginId()); + return new CommonResponse<>(ResponseCode.SUCCESS, userService.authenticate(request)); + } catch (CustomException e) { + return new CommonResponse<>(e.getStatus()); + } + } - LoginResponseDto loginResponseDto = new LoginResponseDto(user.getId(), accessToken, refreshToken); - redisService.setValueWithTTL(refreshToken, user.getId().toString(), 14L, TimeUnit.DAYS); - return new CommonResponse<>(ResponseCode.SUCCESS, loginResponseDto); + // [Post] 로그아웃 + @PostMapping("/logout") + public CommonResponse logout(HttpServletRequest request, @AuthenticationPrincipal UserAccount userAccount) { + try { + userService.postLogout(userAccount.getUsers(), request); + return new CommonResponse<>(ResponseCode.SUCCESS); } catch (CustomException e) { return new CommonResponse<>(e.getStatus()); } diff --git a/src/main/java/ewha/lux/once/domain/user/service/UserService.java b/src/main/java/ewha/lux/once/domain/user/service/UserService.java index 0be16c9..1beb848 100644 --- a/src/main/java/ewha/lux/once/domain/user/service/UserService.java +++ b/src/main/java/ewha/lux/once/domain/user/service/UserService.java @@ -11,6 +11,9 @@ import ewha.lux.once.global.repository.CardRepository; import ewha.lux.once.global.repository.OwnedCardRepository; import ewha.lux.once.global.repository.UsersRepository; +import ewha.lux.once.global.security.JwtAuthFilter; +import ewha.lux.once.global.security.JwtProvider; +import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.security.core.userdetails.User; @@ -29,6 +32,7 @@ import java.util.Date; import java.util.List; import java.util.Optional; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @Service @@ -39,9 +43,12 @@ public class UserService implements UserDetailsService { private final CardRepository cardRepository; private final CardCompanyRepository cardCompanyRepository; private final OwnedCardRepository ownedCardRepository; + private final JwtProvider jwtProvider; private final S3Uploader s3Uploader; + private final RedisTemplate redisTemplate; + private final RedisService redisService; - public Users signup(SignupRequestDto request) throws CustomException, ParseException { + public LoginResponseDto signup(SignupRequestDto request) throws CustomException, ParseException { String loginId = request.getLoginId(); String username = request.getUsername(); String password = request.getPassword(); @@ -77,10 +84,18 @@ public Users signup(SignupRequestDto request) throws CustomException, ParseExcep usersBuilder.birthday(birthday); } - return usersRepository.save(usersBuilder.benefitGoal(100000).build()); + Users newUser = usersRepository.save(usersBuilder.benefitGoal(100000).build()); + + String accessToken = jwtProvider.generateAccessToken(newUser.getLoginId()); + String refreshToken = jwtProvider.generateRefreshToken(newUser.getLoginId()); + + LoginResponseDto loginResponseDto = new LoginResponseDto(newUser.getId(), accessToken, refreshToken); + redisService.setValueWithTTL(refreshToken, newUser.getId().toString(), 14L, TimeUnit.DAYS); + + return loginResponseDto; } - public Users authenticate(SignInRequestDto request) throws CustomException { + public LoginResponseDto authenticate(SignInRequestDto request) throws CustomException { String loginId = request.getLoginId(); String password = request.getPassword(); @@ -93,7 +108,19 @@ public Users authenticate(SignInRequestDto request) throws CustomException { users.setLastLogin(); usersRepository.save(users); - return users; + + String accessToken = jwtProvider.generateAccessToken(users.getLoginId()); + String refreshToken = jwtProvider.generateRefreshToken(users.getLoginId()); + LoginResponseDto loginResponseDto = new LoginResponseDto(users.getId(), accessToken, refreshToken); + redisService.setValueWithTTL(refreshToken, users.getId().toString(), 14L, TimeUnit.DAYS); + + return loginResponseDto; + } + + public void postLogout(Users nowUser, HttpServletRequest request) throws CustomException { + String token = jwtProvider.resolveAccessToken(request); + Long expiration = jwtProvider.getExpiration(token); + redisTemplate.opsForValue().set(token, "logout", expiration, TimeUnit.MILLISECONDS); } public void deleteUsers(Users nowUser) throws CustomException { diff --git a/src/main/java/ewha/lux/once/global/security/JwtProvider.java b/src/main/java/ewha/lux/once/global/security/JwtProvider.java index 65e522d..1203095 100644 --- a/src/main/java/ewha/lux/once/global/security/JwtProvider.java +++ b/src/main/java/ewha/lux/once/global/security/JwtProvider.java @@ -4,11 +4,13 @@ import ewha.lux.once.global.repository.UsersRepository; import ewha.lux.once.domain.user.service.UserService; import io.jsonwebtoken.*; +import jakarta.servlet.http.HttpServletRequest; import lombok.Getter; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; import java.util.*; @@ -17,8 +19,9 @@ public class JwtProvider { private static final long ACCESS_EXPIRE_TIME = 1000l * 60 * 60 * 2; // 2시간 private static final long REFRESH_EXPIRE_TIME = 1000l * 60 * 60 * 24 * 14; // 2주 - private final UserService userService; private final UsersRepository usersRepository; + public static final String TOKEN_PREFIX = "Bearer "; + public static final String HEADER_STRING = "Authorization"; @Getter @Value("${spring.jwt.secret}") @@ -95,5 +98,18 @@ public boolean validateAccessTokenExpiration(String token) { } } + // accessToken 값 가져오기 + public String resolveAccessToken(HttpServletRequest request) { + String token = request.getHeader(JwtProvider.HEADER_STRING); + if (StringUtils.hasText(token) && token.startsWith(JwtProvider.TOKEN_PREFIX)) { + return token.replace(JwtProvider.TOKEN_PREFIX, ""); + } + return null; + } + // accessToken 만료 시간 반환 + public Long getExpiration(String token) { + Claims claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody(); + return claims.getExpiration().getTime(); + } } From 4eb5625b6eb3e3df8483ef0225b3cd7c39f1775f Mon Sep 17 00:00:00 2001 From: julia-heo <100216331+julia-heo@users.noreply.github.com> Date: Tue, 28 May 2024 10:53:25 +0900 Subject: [PATCH 4/6] =?UTF-8?q?feat:=20redis=EC=9C=BC=EB=A1=9C=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8,=20=EB=A1=9C=EA=B7=B8=EC=95=84=EC=9B=83,=20?= =?UTF-8?q?=EC=9E=90=EB=8F=99=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20(#40)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 1 + .../user/controller/UserController.java | 7 +- .../domain/user/service/RedisService.java | 12 +- .../once/domain/user/service/UserService.java | 26 ++-- .../lux/once/global/common/ResponseCode.java | 5 + .../lux/once/global/config/RedisConfig.java | 1 + .../once/global/config/SecurityConfig.java | 1 + .../once/global/security/JwtAuthFilter.java | 130 ++++++++++-------- .../lux/once/global/security/JwtProvider.java | 111 ++++++--------- 9 files changed, 155 insertions(+), 139 deletions(-) diff --git a/build.gradle b/build.gradle index c10190d..9ec06e9 100644 --- a/build.gradle +++ b/build.gradle @@ -42,6 +42,7 @@ dependencies { implementation 'io.jsonwebtoken:jjwt-jackson:0.11.5' implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE' + implementation 'org.springframework.boot:spring-boot-starter-data-redis' } tasks.named('test') { diff --git a/src/main/java/ewha/lux/once/domain/user/controller/UserController.java b/src/main/java/ewha/lux/once/domain/user/controller/UserController.java index 61a68a6..3e140c4 100644 --- a/src/main/java/ewha/lux/once/domain/user/controller/UserController.java +++ b/src/main/java/ewha/lux/once/domain/user/controller/UserController.java @@ -48,15 +48,18 @@ public CommonResponse signin(@RequestBody SignInRequestDto request) { // [Post] 로그아웃 @PostMapping("/logout") - public CommonResponse logout(HttpServletRequest request, @AuthenticationPrincipal UserAccount userAccount) { + @ResponseBody + public CommonResponse logoutPage(HttpServletRequest request,@AuthenticationPrincipal UserAccount userAccount) { try { - userService.postLogout(userAccount.getUsers(), request); + userService.postLogout(request, userAccount.getUsers()); return new CommonResponse<>(ResponseCode.SUCCESS); } catch (CustomException e) { return new CommonResponse<>(e.getStatus()); } } + + // [Delete] 회원 탈퇴 @DeleteMapping("/quit") @ResponseBody diff --git a/src/main/java/ewha/lux/once/domain/user/service/RedisService.java b/src/main/java/ewha/lux/once/domain/user/service/RedisService.java index c5b3232..5649047 100644 --- a/src/main/java/ewha/lux/once/domain/user/service/RedisService.java +++ b/src/main/java/ewha/lux/once/domain/user/service/RedisService.java @@ -2,7 +2,6 @@ import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.stereotype.Service; @@ -12,8 +11,17 @@ @RequiredArgsConstructor public class RedisService { private final RedisTemplate redisTemplate; + private static final String REFRESH_TOKEN_PREFIX = "refreshToken:"; + private static final String ACCESS_TOKEN_BLACKLIST_PREFIX = "blacklistAccessToken:"; - public void setValueWithTTL(String key, Object value, long timeout, TimeUnit unit) { + + public void setRefreshValueWithTTL(String user_id, String refreshToken, long timeout, TimeUnit unit) { + String key = REFRESH_TOKEN_PREFIX + user_id; + ValueOperations valueOperations = redisTemplate.opsForValue(); + valueOperations.set(key, refreshToken, timeout, unit); + } + public void setAccessBlackValueWithTTL(String accessToken, String value, long timeout, TimeUnit unit) { + String key = ACCESS_TOKEN_BLACKLIST_PREFIX + accessToken; ValueOperations valueOperations = redisTemplate.opsForValue(); valueOperations.set(key, value, timeout, unit); } diff --git a/src/main/java/ewha/lux/once/domain/user/service/UserService.java b/src/main/java/ewha/lux/once/domain/user/service/UserService.java index 1beb848..0051845 100644 --- a/src/main/java/ewha/lux/once/domain/user/service/UserService.java +++ b/src/main/java/ewha/lux/once/domain/user/service/UserService.java @@ -43,10 +43,13 @@ public class UserService implements UserDetailsService { private final CardRepository cardRepository; private final CardCompanyRepository cardCompanyRepository; private final OwnedCardRepository ownedCardRepository; + + private final JwtAuthFilter jwtAuthFilter; private final JwtProvider jwtProvider; private final S3Uploader s3Uploader; private final RedisTemplate redisTemplate; private final RedisService redisService; + private static final String REFRESH_TOKEN_PREFIX = "refreshToken:"; public LoginResponseDto signup(SignupRequestDto request) throws CustomException, ParseException { String loginId = request.getLoginId(); @@ -86,11 +89,11 @@ public LoginResponseDto signup(SignupRequestDto request) throws CustomException, Users newUser = usersRepository.save(usersBuilder.benefitGoal(100000).build()); - String accessToken = jwtProvider.generateAccessToken(newUser.getLoginId()); - String refreshToken = jwtProvider.generateRefreshToken(newUser.getLoginId()); + String accessToken = jwtProvider.createAccessToken(newUser.getLoginId()); + String refreshToken = jwtProvider.createRefreshToken(newUser.getLoginId()); LoginResponseDto loginResponseDto = new LoginResponseDto(newUser.getId(), accessToken, refreshToken); - redisService.setValueWithTTL(refreshToken, newUser.getId().toString(), 14L, TimeUnit.DAYS); + redisService.setRefreshValueWithTTL(newUser.getId().toString(), refreshToken, 14L, TimeUnit.DAYS); return loginResponseDto; } @@ -109,18 +112,21 @@ public LoginResponseDto authenticate(SignInRequestDto request) throws CustomExce users.setLastLogin(); usersRepository.save(users); - String accessToken = jwtProvider.generateAccessToken(users.getLoginId()); - String refreshToken = jwtProvider.generateRefreshToken(users.getLoginId()); + String accessToken = jwtProvider.createAccessToken(users.getLoginId()); + String refreshToken = jwtProvider.createRefreshToken(users.getLoginId()); LoginResponseDto loginResponseDto = new LoginResponseDto(users.getId(), accessToken, refreshToken); - redisService.setValueWithTTL(refreshToken, users.getId().toString(), 14L, TimeUnit.DAYS); + redisService.setRefreshValueWithTTL(users.getId().toString(), refreshToken, 14L, TimeUnit.DAYS); return loginResponseDto; } - public void postLogout(Users nowUser, HttpServletRequest request) throws CustomException { - String token = jwtProvider.resolveAccessToken(request); - Long expiration = jwtProvider.getExpiration(token); - redisTemplate.opsForValue().set(token, "logout", expiration, TimeUnit.MILLISECONDS); + public void postLogout(HttpServletRequest request, Users nowuser) throws CustomException { + String accessToken = jwtAuthFilter.resolveToken(request,jwtAuthFilter.HEADER_KEY); + Long expiration = jwtProvider.getExpiration(accessToken); + redisService.setAccessBlackValueWithTTL(accessToken,"logout",expiration, TimeUnit.MILLISECONDS); + // 리프레시 토큰 삭제 + redisService.deleteValue(REFRESH_TOKEN_PREFIX+nowuser.getId().toString()); + System.out.println("왕왕왕왕왕"); } public void deleteUsers(Users nowUser) throws CustomException { diff --git a/src/main/java/ewha/lux/once/global/common/ResponseCode.java b/src/main/java/ewha/lux/once/global/common/ResponseCode.java index 28c7723..63be796 100644 --- a/src/main/java/ewha/lux/once/global/common/ResponseCode.java +++ b/src/main/java/ewha/lux/once/global/common/ResponseCode.java @@ -17,6 +17,7 @@ public enum ResponseCode { 2000~ : Request 오류 */ + // ===================================== /* 3000~ : Response 오류 @@ -26,6 +27,10 @@ public enum ResponseCode { INVALID_USER_ID(3001, false, "아이디가 존재하지 않습니다."), FAILED_TO_LOGIN(3002, false, "비밀번호가 일치하지 않습니다."), DUPLICATED_USER_NAME(3003, false,"이미 존재하는 아이디입니다."), + UNAUTHORIZED_REFRESH(3004, false, "refresh token이 만료되었습니다. 다시 로그인해주세요"), + UNAUTHORIZED(3005, false, "access token이 유효하지 않습니다."), + INVALID_REFRESH(3006, false, "refresh token이 유효하지 않습니다."), + BLACKLISTED_TOKEN(3007, false, "블랙리스트에 등록된 토큰입니다."), // 3100~ : card 관련 오류 CARD_NOT_FOUND(3100, false,"존재하지 않는 카드입니다."), diff --git a/src/main/java/ewha/lux/once/global/config/RedisConfig.java b/src/main/java/ewha/lux/once/global/config/RedisConfig.java index f8f86b0..c76c82e 100644 --- a/src/main/java/ewha/lux/once/global/config/RedisConfig.java +++ b/src/main/java/ewha/lux/once/global/config/RedisConfig.java @@ -19,6 +19,7 @@ public class RedisConfig { @Bean public RedisConnectionFactory redisConnectionFactory() { return new LettuceConnectionFactory(redisProperties.getHost(), redisProperties.getPort()); + // return new LettuceConnectionFactory("localhost", redisProperties.getPort()); // 로컬 } @Bean diff --git a/src/main/java/ewha/lux/once/global/config/SecurityConfig.java b/src/main/java/ewha/lux/once/global/config/SecurityConfig.java index 157d7a7..59e3ac4 100644 --- a/src/main/java/ewha/lux/once/global/config/SecurityConfig.java +++ b/src/main/java/ewha/lux/once/global/config/SecurityConfig.java @@ -59,6 +59,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .requestMatchers("/user/login").permitAll() .requestMatchers("/user/auto").permitAll() .requestMatchers("/user/card/search").permitAll() + .requestMatchers("/user/logout").permitAll() .anyRequest().authenticated() ) .addFilterBefore(new JwtAuthFilter(jwtProvider, redisService), UsernamePasswordAuthenticationFilter.class); diff --git a/src/main/java/ewha/lux/once/global/security/JwtAuthFilter.java b/src/main/java/ewha/lux/once/global/security/JwtAuthFilter.java index 6d7441d..35f50ce 100644 --- a/src/main/java/ewha/lux/once/global/security/JwtAuthFilter.java +++ b/src/main/java/ewha/lux/once/global/security/JwtAuthFilter.java @@ -3,7 +3,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import ewha.lux.once.domain.user.dto.LoginResponseDto; import ewha.lux.once.domain.user.service.RedisService; -import ewha.lux.once.global.common.CustomException; +import ewha.lux.once.global.common.ResponseCode; import ewha.lux.once.global.common.UserAccount; import ewha.lux.once.domain.user.entity.Users; import ewha.lux.once.global.common.ResponseDto; @@ -13,27 +13,28 @@ import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.http.ResponseEntity; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper; import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.util.ObjectUtils; -import org.springframework.util.StringUtils; +import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; import java.io.IOException; +import java.io.PrintWriter; @Slf4j @RequiredArgsConstructor +@Component public class JwtAuthFilter extends OncePerRequestFilter { private final JwtProvider jwtProvider; private final RedisService redisService; public static final String HEADER_KEY = "Authorization"; public static final String REFRESH_HEADER_KEY = "Authorization-refresh"; public static final String PREFIX = "Bearer "; + private static final String REFRESH_TOKEN_PREFIX = "refreshToken:"; private final GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper(); @@ -43,52 +44,85 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse String accessToken = resolveToken(request, HEADER_KEY); String refreshToken = resolveToken(request, REFRESH_HEADER_KEY); - // 자동 로그인 요청인 경우 - if(request.getRequestURI().equals("/user/auto")) { - if ("Deprecated".equals(redisService.getValue(refreshToken))) { - response.setContentType("application/json"); - response.setCharacterEncoding("utf-8"); - response.setStatus(HttpServletResponse.SC_BAD_REQUEST); - response.getWriter().write(new ObjectMapper().writeValueAsString(ResponseEntity.ok(ResponseDto.response(1000, true, "refresh token이 만료되었습니다. 다시 로그인해주세요")))); + if (accessToken != null && jwtProvider.validateToken(accessToken)) { + // access token있고 유효할 때 + if(jwtProvider.isAccessTokenLoggedOut(accessToken)){ + // 블랙리스트 + sendErrorResponse(response,403,ResponseCode.BLACKLISTED_TOKEN); return; } - // 토큰 유효성 검사 - if (!jwtProvider.validateAccessTokenExpiration(accessToken)) { // accesstoken이 유효한 경우 - Users users = jwtProvider.validateTokenAndGetUsers(accessToken); - LoginResponseDto loginResponseDto = new LoginResponseDto(users.getId(), accessToken, refreshToken); - - response.setContentType("application/json"); - response.setCharacterEncoding("utf-8"); - response.setStatus(HttpServletResponse.SC_OK); - response.getWriter().write(new ObjectMapper().writeValueAsString(ResponseEntity.ok(ResponseDto.response(1000, true, "access token이 검증되었습니다.", loginResponseDto)))); - return; - } else if (!jwtProvider.validateAccessTokenExpiration(refreshToken)) { // accesstoken 만료, refreshtoken이 유효한 경우 - Users users = jwtProvider.validateTokenAndGetUsers(refreshToken); - String newAccessToken = jwtProvider.generateAccessToken(users.getLoginId()); - LoginResponseDto loginResponseDto = new LoginResponseDto(users.getId(), newAccessToken, refreshToken); - - response.setContentType("application/json"); - response.setCharacterEncoding("utf-8"); - response.setStatus(HttpServletResponse.SC_OK); - response.getWriter().write(new ObjectMapper().writeValueAsString(ResponseEntity.ok(ResponseDto.response(1000,true, "access token이 재발급되었습니다.", loginResponseDto)))); - return; - } else { // refreshtoken 만료 - response.setContentType("application/json"); - response.setCharacterEncoding("utf-8"); - response.setStatus(HttpServletResponse.SC_BAD_REQUEST); - response.getWriter().write(new ObjectMapper().writeValueAsString(ResponseEntity.ok(ResponseDto.response(1000, true, "refresh token이 만료되었습니다. 다시 로그인해주세요")))); - return; - } - } - if(StringUtils.hasText(accessToken) && jwtProvider.validateToken(accessToken)){ - Users users = jwtProvider.validateTokenAndGetUsers(accessToken); + // users 찾아 인증정보 저장 + Users users = jwtProvider.extractUsersFromToken(accessToken); saveAuthentication(users); - filterChain.doFilter(request, response); + + } else if (refreshToken != null) { + if (jwtProvider.validateToken(refreshToken)) { + // refresh token있고 유효할 때 + + Users users = jwtProvider.extractUsersFromToken(refreshToken); + String redisRefreshToken = (String) redisService.getValue(REFRESH_TOKEN_PREFIX+users.getId().toString()); + + if (redisRefreshToken != null && redisRefreshToken.equals(refreshToken)) { + // access token 재발급 + String newAccessToken = jwtProvider.createAccessToken(users.getLoginId()); + + response.setHeader(HEADER_KEY, PREFIX + newAccessToken); + + response.setContentType("application/json"); + response.setCharacterEncoding("utf-8"); + response.setStatus(HttpServletResponse.SC_OK); + LoginResponseDto loginResponseDto = new LoginResponseDto(users.getId(), newAccessToken, refreshToken); + + ResponseDto responseDto1 = ResponseDto.response(1000, true, "access token이 재발급되었습니다.", loginResponseDto); + + PrintWriter writer = response.getWriter(); + writer.write(new ObjectMapper().writeValueAsString(responseDto1)); + writer.flush(); + + saveAuthentication(users); + return; + + } else { + // refresh token이 유효하지 않을 때 + sendErrorResponse(response,403,ResponseCode.INVALID_REFRESH); + return; + } + } else { + // refresh token이 만료되었을 때 + sendErrorResponse(response,403,ResponseCode.UNAUTHORIZED_REFRESH); + return; + } + } else if (accessToken != null) { + // access token이 유효하지 않을 때 + sendErrorResponse(response,403,ResponseCode.UNAUTHORIZED); return; } + System.out.println("왜"); filterChain.doFilter(request, response); + + } + + private void sendErrorResponse(HttpServletResponse response, int statusCode, ResponseCode code) throws IOException { + response.setStatus(statusCode); + response.setContentType("application/json"); + response.setCharacterEncoding("UTF-8"); + + PrintWriter writer = response.getWriter(); + ResponseDto responseDto = ResponseDto.response(code.getCode(), code.isInSuccess(), code.getMessage()); + writer.write(new ObjectMapper().writeValueAsString(responseDto)); + writer.flush(); + } + + // Token만 분리해 반환 (Bearer 제거) + public String resolveToken(HttpServletRequest request, String headerKey) { + String bearerToken = request.getHeader(headerKey); + if (bearerToken != null && bearerToken.startsWith(PREFIX)) { + return bearerToken.substring(PREFIX.length()); + } + return null; } + public void saveAuthentication(Users users) { UserAccount userAccount = new UserAccount(users); @@ -103,16 +137,4 @@ public void saveAuthentication(Users users) { SecurityContextHolder.setContext(context); } - // Token만 분리해 반환 - private String resolveToken(HttpServletRequest request, String key){ - String token = request.getHeader(key); - - // key의 헤더가 존재하고, Bearer로 시작한다면 - if(!ObjectUtils.isEmpty(token) && token.startsWith(PREFIX)) { - return token.substring(PREFIX.length()); - } - - return null; - } - } diff --git a/src/main/java/ewha/lux/once/global/security/JwtProvider.java b/src/main/java/ewha/lux/once/global/security/JwtProvider.java index 1203095..632226f 100644 --- a/src/main/java/ewha/lux/once/global/security/JwtProvider.java +++ b/src/main/java/ewha/lux/once/global/security/JwtProvider.java @@ -2,114 +2,83 @@ import ewha.lux.once.domain.user.entity.Users; import ewha.lux.once.global.repository.UsersRepository; -import ewha.lux.once.domain.user.service.UserService; +import org.springframework.data.redis.core.RedisTemplate; import io.jsonwebtoken.*; -import jakarta.servlet.http.HttpServletRequest; import lombok.Getter; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; import java.util.*; @Component @RequiredArgsConstructor public class JwtProvider { + private static final long ACCESS_EXPIRE_TIME = 1000l * 60 * 60 * 2; // 2시간 private static final long REFRESH_EXPIRE_TIME = 1000l * 60 * 60 * 24 * 14; // 2주 + + private final UsersRepository usersRepository; - public static final String TOKEN_PREFIX = "Bearer "; - public static final String HEADER_STRING = "Authorization"; + private final RedisTemplate redisTemplate; + private static final String ACCESS_TOKEN_BLACKLIST_PREFIX = "blacklistAccessToken:"; + @Getter @Value("${spring.jwt.secret}") private String secretKey; - // 토큰 생성 - public String generateToken(String loginId,Long accessTokenValidTime,boolean isAccessToken) { - Claims claims = Jwts.claims().setSubject(loginId); - String subject = isAccessToken ? "access" : "refresh"; - - claims.put("authority", subject); // 권한 - + public String createAccessToken(String userId) { Date now = new Date(); - Date expiration = new Date(now.getTime() + accessTokenValidTime); // 만료 시간 + Date validity = new Date(now.getTime() + ACCESS_EXPIRE_TIME); return Jwts.builder() - .setClaims(claims) + .setSubject(userId) .setIssuedAt(now) - .setExpiration(expiration) - .signWith(SignatureAlgorithm.HS512, secretKey) // (비밀키, 해싱 알고리즘) + .setExpiration(validity) + .signWith(SignatureAlgorithm.HS256, secretKey) .compact(); } - // 액세스 토큰 생성 - public String generateAccessToken(String loginId) { - return generateToken(loginId, ACCESS_EXPIRE_TIME,true); - } - - // 리프레쉬 토큰 생성 - public String generateRefreshToken(String loginId) { - return generateToken(loginId, REFRESH_EXPIRE_TIME,false); - } - - // 토큰 유효성 확인, t/f 반환 - public boolean validateToken(String token) throws ExpiredJwtException { - Claims claims = Jwts.parserBuilder() - .setSigningKey(secretKey) - .build() - .parseClaimsJws(token) - .getBody(); - - Date expiration = claims.getExpiration(); + public String createRefreshToken(String userId) { Date now = new Date(); + Date validity = new Date(now.getTime() + REFRESH_EXPIRE_TIME); - if (expiration.before(now)) { - return false; - } - - return true; + return Jwts.builder() + .setSubject(userId) + .setIssuedAt(now) + .setExpiration(validity) + .signWith(SignatureAlgorithm.HS256, secretKey) + .compact(); } - // 토큰 검증 및 payload 추출 (토큰으로 현재 Users 찾아 반환) - public Users validateTokenAndGetUsers(String token){ - Claims claims = Jwts.parserBuilder() - .setSigningKey(secretKey) - .build() - .parseClaimsJws(token) - .getBody(); - String loginId = claims.getSubject(); + // 토큰으로 User찾아 반환 + public Users extractUsersFromToken(String token) { + + String loginId = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody().getSubject(); return usersRepository.findByLoginId(loginId).get(); } - - // 토큰 만료 여부 확인 - public boolean validateAccessTokenExpiration(String token) { - try{ - Jws claims = Jwts.parser() - .setSigningKey(secretKey) - .parseClaimsJws(token); - - return claims.getBody().getExpiration().before(new Date()); // 현재보다 만료가 이전인지 확인 - } - catch (ExpiredJwtException ignored){ - return true; - } + // accessToken 만료 시간 반환 + public Long getExpiration(String token) { + Claims claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody(); + return claims.getExpiration().getTime(); } - // accessToken 값 가져오기 - public String resolveAccessToken(HttpServletRequest request) { - String token = request.getHeader(JwtProvider.HEADER_STRING); - if (StringUtils.hasText(token) && token.startsWith(JwtProvider.TOKEN_PREFIX)) { - return token.replace(JwtProvider.TOKEN_PREFIX, ""); + + public boolean validateToken(String token) { + try { + Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token); + return true; + } catch (Exception e) { + return false; } - return null; } - // accessToken 만료 시간 반환 - public Long getExpiration(String token) { - Claims claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody(); - return claims.getExpiration().getTime(); + public boolean isAccessTokenLoggedOut(String accessToken) { + // Redis에서 액세스 토큰의 상태를 가져옴 + String key = ACCESS_TOKEN_BLACKLIST_PREFIX + accessToken; + // 로그아웃 상태인지 확인 + return redisTemplate.hasKey(key); } } From 963f7540ef382c9e25f73728a69f5b5b04dd95d4 Mon Sep 17 00:00:00 2001 From: julia-heo <100216331+julia-heo@users.noreply.github.com> Date: Tue, 28 May 2024 11:27:54 +0900 Subject: [PATCH 5/6] =?UTF-8?q?feat:=20=EC=9E=90=EB=8F=99=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20access=20token=20=EC=9C=A0=ED=9A=A8?= =?UTF-8?q?=ED=95=9C=20=EA=B2=BD=EC=9A=B0=20=EC=B2=98=EB=A6=AC=20(#40)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../once/domain/user/controller/UserController.java | 10 ++++++---- .../java/ewha/lux/once/global/common/ResponseCode.java | 1 + .../ewha/lux/once/global/security/JwtAuthFilter.java | 1 - 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/ewha/lux/once/domain/user/controller/UserController.java b/src/main/java/ewha/lux/once/domain/user/controller/UserController.java index 3e140c4..e0bbe8d 100644 --- a/src/main/java/ewha/lux/once/domain/user/controller/UserController.java +++ b/src/main/java/ewha/lux/once/domain/user/controller/UserController.java @@ -2,10 +2,7 @@ import ewha.lux.once.domain.user.dto.*; import ewha.lux.once.domain.user.service.UserService; -import ewha.lux.once.global.common.CommonResponse; -import ewha.lux.once.global.common.CustomException; -import ewha.lux.once.global.common.ResponseCode; -import ewha.lux.once.global.common.UserAccount; +import ewha.lux.once.global.common.*; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import org.springframework.data.repository.query.Param; @@ -45,6 +42,11 @@ public CommonResponse signin(@RequestBody SignInRequestDto request) { return new CommonResponse<>(e.getStatus()); } } + // [Post] 자동로그인 + @PostMapping("/auto") + public CommonResponse autologinPage() { + return new CommonResponse<>(ResponseCode.VALID_ACCESS_TOKEN); + } // [Post] 로그아웃 @PostMapping("/logout") diff --git a/src/main/java/ewha/lux/once/global/common/ResponseCode.java b/src/main/java/ewha/lux/once/global/common/ResponseCode.java index 63be796..95e34af 100644 --- a/src/main/java/ewha/lux/once/global/common/ResponseCode.java +++ b/src/main/java/ewha/lux/once/global/common/ResponseCode.java @@ -12,6 +12,7 @@ public enum ResponseCode { CHANGE_MYPAGE_SUCCESS(1002, true, "내 정보 수정을 성공했습니다."), RELEASE_MAINCARD_SUCCESS(1003, true, "주카드 해제를 성공했습니다."), DELETE_CARD_SUCCESS(1004, true, "등록 카드 삭제에 성공했습니다."), + VALID_ACCESS_TOKEN(1005, true, "유효한 access token입니다."), /* 2000~ : Request 오류 diff --git a/src/main/java/ewha/lux/once/global/security/JwtAuthFilter.java b/src/main/java/ewha/lux/once/global/security/JwtAuthFilter.java index 35f50ce..79fc6db 100644 --- a/src/main/java/ewha/lux/once/global/security/JwtAuthFilter.java +++ b/src/main/java/ewha/lux/once/global/security/JwtAuthFilter.java @@ -98,7 +98,6 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse sendErrorResponse(response,403,ResponseCode.UNAUTHORIZED); return; } - System.out.println("왜"); filterChain.doFilter(request, response); } From 9368e09e84bc20454f6b6952f72e31a911d47425 Mon Sep 17 00:00:00 2001 From: julia-heo <100216331+julia-heo@users.noreply.github.com> Date: Tue, 28 May 2024 15:43:10 +0900 Subject: [PATCH 6/6] =?UTF-8?q?fix:=20import=20=EC=B6=94=EA=B0=80=20(#40)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ewha/lux/once/domain/user/controller/UserController.java | 1 + src/main/java/ewha/lux/once/domain/user/service/UserService.java | 1 + 2 files changed, 2 insertions(+) diff --git a/src/main/java/ewha/lux/once/domain/user/controller/UserController.java b/src/main/java/ewha/lux/once/domain/user/controller/UserController.java index cff1a36..2c26d1a 100644 --- a/src/main/java/ewha/lux/once/domain/user/controller/UserController.java +++ b/src/main/java/ewha/lux/once/domain/user/controller/UserController.java @@ -14,6 +14,7 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; +import ewha.lux.once.global.security.JwtProvider; import java.io.IOException; import java.text.ParseException; diff --git a/src/main/java/ewha/lux/once/domain/user/service/UserService.java b/src/main/java/ewha/lux/once/domain/user/service/UserService.java index b7864f9..7eda671 100644 --- a/src/main/java/ewha/lux/once/domain/user/service/UserService.java +++ b/src/main/java/ewha/lux/once/domain/user/service/UserService.java @@ -30,6 +30,7 @@ import java.util.*; import java.util.stream.Collectors; +import java.util.concurrent.TimeUnit; @Service @RequiredArgsConstructor