diff --git a/src/main/java/com/onnoff/onnoff/auth/config/FilterConfig.java b/src/main/java/com/onnoff/onnoff/auth/config/FilterConfig.java new file mode 100644 index 0000000..9a66ac2 --- /dev/null +++ b/src/main/java/com/onnoff/onnoff/auth/config/FilterConfig.java @@ -0,0 +1,28 @@ +package com.onnoff.onnoff.auth.config; + +import com.onnoff.onnoff.auth.jwt.filter.JwtAuthFilter; +import com.onnoff.onnoff.auth.jwt.filter.UserInterceptor; +import com.onnoff.onnoff.auth.jwt.service.JwtUtil; +import com.onnoff.onnoff.auth.jwt.service.TokenProvider; +import com.onnoff.onnoff.domain.user.service.UserService; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@RequiredArgsConstructor +public class FilterConfig { + private final TokenProvider tokenProvider; + private final UserService userService; + private final JwtUtil jwtUtil; + + @Bean + public JwtAuthFilter jwtAuthFilter() { + return new JwtAuthFilter(tokenProvider); + } + + @Bean + public UserInterceptor userInterceptor() { + return new UserInterceptor(userService, jwtUtil); + } +} \ No newline at end of file diff --git a/src/main/java/com/onnoff/onnoff/auth/config/WebConfig.java b/src/main/java/com/onnoff/onnoff/auth/config/WebConfig.java index e86b325..2268ea2 100644 --- a/src/main/java/com/onnoff/onnoff/auth/config/WebConfig.java +++ b/src/main/java/com/onnoff/onnoff/auth/config/WebConfig.java @@ -3,9 +3,6 @@ import com.onnoff.onnoff.auth.jwt.filter.JwtAuthFilter; import com.onnoff.onnoff.auth.jwt.filter.UserInterceptor; -import com.onnoff.onnoff.auth.jwt.service.JwtTokenProvider; -import com.onnoff.onnoff.auth.jwt.service.JwtUtil; -import com.onnoff.onnoff.domain.user.service.UserService; import jakarta.persistence.EntityManagerFactory; import lombok.RequiredArgsConstructor; import org.springframework.boot.web.servlet.FilterRegistrationBean; @@ -18,14 +15,13 @@ @Configuration @RequiredArgsConstructor public class WebConfig implements WebMvcConfigurer { - private final JwtTokenProvider jwtTokenProvider; - private final JwtUtil jwtUtil; - private final UserService userService; + private final JwtAuthFilter jwtAuthFilter; private final EntityManagerFactory entityManagerFactory; + private final UserInterceptor userInterceptor; @Bean public FilterRegistrationBean jwtFilterRegistration() { FilterRegistrationBean registration = new FilterRegistrationBean<>(); - registration.setFilter(new JwtAuthFilter(jwtTokenProvider)); // 필터 인스턴스 설정 + registration.setFilter(jwtAuthFilter); // 필터 인스턴스 설정 registration.addUrlPatterns("/*"); //서블릿 컨택스트에서 /*는 모든 요청, /**는 인식되지 않음 registration.setOrder(1); // 필터의 순서 설정. 값이 낮을수록 먼저 실행 return registration; @@ -37,7 +33,7 @@ public void addInterceptors(InterceptorRegistry registry) { openEntityManagerInViewInterceptor.setEntityManagerFactory(entityManagerFactory); registry.addWebRequestInterceptor(openEntityManagerInViewInterceptor); - registry.addInterceptor(new UserInterceptor(userService, jwtUtil)) + registry.addInterceptor(userInterceptor) .addPathPatterns("/**") // 스프링 경로는 /*와 /**이 다름 .excludePathPatterns("/swagger-ui/**", "/v3/api-docs/**", "/oauth2/**", "/health", "/token/**" , "/message/**", "/enums/**", "/users/nickname"); diff --git a/src/main/java/com/onnoff/onnoff/auth/controller/LoginController.java b/src/main/java/com/onnoff/onnoff/auth/controller/LoginController.java index a3545d6..def695f 100644 --- a/src/main/java/com/onnoff/onnoff/auth/controller/LoginController.java +++ b/src/main/java/com/onnoff/onnoff/auth/controller/LoginController.java @@ -10,8 +10,8 @@ import com.onnoff.onnoff.auth.feignClient.dto.TokenResponse; import com.onnoff.onnoff.auth.feignClient.dto.kakao.KakaoOauth2DTO; import com.onnoff.onnoff.auth.jwt.dto.JwtToken; -import com.onnoff.onnoff.auth.jwt.service.JwtTokenProvider; import com.onnoff.onnoff.auth.jwt.service.JwtUtil; +import com.onnoff.onnoff.auth.jwt.service.TokenProvider; import com.onnoff.onnoff.auth.service.AppleLoginService; import com.onnoff.onnoff.auth.service.KakaoLoginService; import com.onnoff.onnoff.domain.user.User; @@ -34,7 +34,7 @@ public class LoginController { private final KakaoLoginService kakaoLoginService; private final AppleLoginService appleLoginService; private final UserService userService; - private final JwtTokenProvider jwtTokenProvider; + private final TokenProvider tokenProvider; private final JwtUtil jwtUtil; @Value("${kakao.redirect-uri}") @@ -135,14 +135,14 @@ public ApiResponse validateAppleToken(@RequestBody Log public ApiResponse validateServerToken(@RequestBody JwtToken tokenDTO){ String accessToken = tokenDTO.getAccessToken(); String refreshToken = tokenDTO.getRefreshToken(); - if( jwtTokenProvider.verifyToken(accessToken) ){ + if( tokenProvider.verifyToken(accessToken) ){ // accessToken 유효 String userId = jwtUtil.getUserId(accessToken); User user = userService.getUser(Long.valueOf(userId)); UserResponseDTO.LoginDTO loginDTO = UserConverter.toLoginDTO(accessToken, refreshToken); return ApiResponse.onSuccess(loginDTO); } - if (jwtTokenProvider.verifyToken(refreshToken)) { + if ( tokenProvider.verifyToken(refreshToken)) { //refreshToken 유효 String userId = jwtUtil.getUserId(refreshToken); User user = userService.getUser(Long.valueOf(userId)); diff --git a/src/main/java/com/onnoff/onnoff/auth/dto/LoginRequestDTO.java b/src/main/java/com/onnoff/onnoff/auth/dto/LoginRequestDTO.java index 9b78e65..4afcf06 100644 --- a/src/main/java/com/onnoff/onnoff/auth/dto/LoginRequestDTO.java +++ b/src/main/java/com/onnoff/onnoff/auth/dto/LoginRequestDTO.java @@ -23,6 +23,7 @@ public static class KakaoTokenValidateDTO{ @Getter public static class AdditionalInfo{ + private String nickname; private String fieldOfWork; private String job; private String experienceYear; diff --git a/src/main/java/com/onnoff/onnoff/auth/feignClient/client/AppleAuthClient.java b/src/main/java/com/onnoff/onnoff/auth/feignClient/client/AppleAuthClient.java index 165d31d..45277f6 100644 --- a/src/main/java/com/onnoff/onnoff/auth/feignClient/client/AppleAuthClient.java +++ b/src/main/java/com/onnoff/onnoff/auth/feignClient/client/AppleAuthClient.java @@ -1,17 +1,17 @@ package com.onnoff.onnoff.auth.feignClient.client; +import com.onnoff.onnoff.auth.feignClient.config.FeignConfig; import com.onnoff.onnoff.auth.feignClient.dto.JwkResponse; import com.onnoff.onnoff.auth.feignClient.dto.TokenResponse; import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import java.util.Map; -@FeignClient(name = "apple-auth-client",url = "https://appleid.apple.com/auth") +@FeignClient(name = "apple-auth-client",url = "https://appleid.apple.com/auth", configuration = FeignConfig.class) public interface AppleAuthClient{ @GetMapping("/keys") JwkResponse.JwkSet getKeys(); @@ -20,6 +20,6 @@ public interface AppleAuthClient{ TokenResponse getToken(@RequestBody Map requestBody); //회원 탈퇴 메서드 -// @GetMapping("/revoke") -// KakaoOauth2DTO.TokenValidateResponseDTO getTokenValidate(@RequestHeader("Authorization") String accessToken); + @PostMapping(value ="/oauth2/v2/revoke", consumes = "application/x-www-form-urlencoded") + void revokeTokens(@RequestBody Map requestBody); } diff --git a/src/main/java/com/onnoff/onnoff/auth/feignClient/client/KakaoApiClient.java b/src/main/java/com/onnoff/onnoff/auth/feignClient/client/KakaoApiClient.java index 7a5a304..76c423f 100644 --- a/src/main/java/com/onnoff/onnoff/auth/feignClient/client/KakaoApiClient.java +++ b/src/main/java/com/onnoff/onnoff/auth/feignClient/client/KakaoApiClient.java @@ -3,8 +3,11 @@ import com.onnoff.onnoff.auth.feignClient.config.FeignConfig; import com.onnoff.onnoff.auth.feignClient.dto.kakao.KakaoOauth2DTO; import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import java.util.Map; + /* 토큰 유효성 검증 하고 사용자 정보 가져오는 client */ @@ -15,5 +18,7 @@ public interface KakaoApiClient { KakaoOauth2DTO.TokenValidateResponseDTO getTokenValidate(@RequestHeader("Authorization") String accessToken); @GetMapping(value = "/v1/oidc/userinfo") KakaoOauth2DTO.UserInfoResponseDTO getUserInfo(@RequestHeader("Authorization") String accessToken); + @PostMapping(value = "/v1/user/unlink", consumes = "application/x-www-form-urlencoded") + ResponseEntity unlink(@RequestHeader("Authorization") String adminKey, @RequestBody Map requestBody); } diff --git a/src/main/java/com/onnoff/onnoff/auth/feignClient/dto/apple/RevokeTokenReqeust.java b/src/main/java/com/onnoff/onnoff/auth/feignClient/dto/apple/RevokeTokenReqeust.java new file mode 100644 index 0000000..1b94d4f --- /dev/null +++ b/src/main/java/com/onnoff/onnoff/auth/feignClient/dto/apple/RevokeTokenReqeust.java @@ -0,0 +1,28 @@ +package com.onnoff.onnoff.auth.feignClient.dto.apple; + + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +@Getter +@Builder +@AllArgsConstructor +public class RevokeTokenReqeust { + private String clientId; + private String clientSecret; + private String token; + private String tokenTypeHint; + + public MultiValueMap toUrlEncoded(){ + LinkedMultiValueMap urlEncoded = new LinkedMultiValueMap<>(); + urlEncoded.add("client_id", clientId); + urlEncoded.add("client_secret", clientSecret); + urlEncoded.add("token", token); + urlEncoded.add("token_type_hint", "refresh_token"); + return urlEncoded; + } +} diff --git a/src/main/java/com/onnoff/onnoff/auth/feignClient/dto/kakao/UnlinkRequest.java b/src/main/java/com/onnoff/onnoff/auth/feignClient/dto/kakao/UnlinkRequest.java new file mode 100644 index 0000000..bead91c --- /dev/null +++ b/src/main/java/com/onnoff/onnoff/auth/feignClient/dto/kakao/UnlinkRequest.java @@ -0,0 +1,22 @@ +package com.onnoff.onnoff.auth.feignClient.dto.kakao; + + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +@Builder +@AllArgsConstructor +public class UnlinkRequest { + private String targetIdType; + private String targetId; + + public MultiValueMap toUrlEncoded(){ + LinkedMultiValueMap urlEncoded = new LinkedMultiValueMap<>(); + urlEncoded.add("target_id_type", targetIdType); + urlEncoded.add("target_id", targetId); + return urlEncoded; + } +} diff --git a/src/main/java/com/onnoff/onnoff/auth/jwt/filter/JwtAuthFilter.java b/src/main/java/com/onnoff/onnoff/auth/jwt/filter/JwtAuthFilter.java index a4a9139..94a2a3b 100644 --- a/src/main/java/com/onnoff/onnoff/auth/jwt/filter/JwtAuthFilter.java +++ b/src/main/java/com/onnoff/onnoff/auth/jwt/filter/JwtAuthFilter.java @@ -8,7 +8,7 @@ */ -import com.onnoff.onnoff.auth.jwt.service.JwtTokenProvider; +import com.onnoff.onnoff.auth.jwt.service.TokenProvider; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; @@ -16,7 +16,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; -import org.springframework.util.StringUtils; import org.springframework.web.filter.OncePerRequestFilter; import java.io.IOException; @@ -24,7 +23,7 @@ @Slf4j @RequiredArgsConstructor public class JwtAuthFilter extends OncePerRequestFilter { - private final JwtTokenProvider jwtTokenProvider; + private final TokenProvider tokenProvider; private final static String[] ignorePrefix = {"/swagger-ui", "/v3/api-docs", "/oauth2", "/health", "/token/validate" , "/message", "/enums", "/users/nickname"}; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { @@ -43,7 +42,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse if (authHeader != null && authHeader.startsWith("Bearer ")) { accessToken = authHeader.substring(7); } - if (jwtTokenProvider.verifyToken(accessToken)){ + if (tokenProvider.verifyToken(accessToken)){ log.info("인증성공"); filterChain.doFilter(request, response); } diff --git a/src/main/java/com/onnoff/onnoff/auth/jwt/service/JwtTokenProvider.java b/src/main/java/com/onnoff/onnoff/auth/jwt/service/JwtTokenProvider.java index 35226fd..dee3f7d 100644 --- a/src/main/java/com/onnoff/onnoff/auth/jwt/service/JwtTokenProvider.java +++ b/src/main/java/com/onnoff/onnoff/auth/jwt/service/JwtTokenProvider.java @@ -23,7 +23,7 @@ @Slf4j @Service @RequiredArgsConstructor -public class JwtTokenProvider { +public class JwtTokenProvider implements TokenProvider { @Value("${spring.jwt.secret}") private String secret; private SecretKey secretkey; diff --git a/src/main/java/com/onnoff/onnoff/auth/jwt/service/TokenProvider.java b/src/main/java/com/onnoff/onnoff/auth/jwt/service/TokenProvider.java new file mode 100644 index 0000000..f314a0b --- /dev/null +++ b/src/main/java/com/onnoff/onnoff/auth/jwt/service/TokenProvider.java @@ -0,0 +1,5 @@ +package com.onnoff.onnoff.auth.jwt.service; + +public interface TokenProvider { + boolean verifyToken(String token); +} diff --git a/src/main/java/com/onnoff/onnoff/auth/service/AppleLoginService.java b/src/main/java/com/onnoff/onnoff/auth/service/AppleLoginService.java index 725a037..ee75b40 100644 --- a/src/main/java/com/onnoff/onnoff/auth/service/AppleLoginService.java +++ b/src/main/java/com/onnoff/onnoff/auth/service/AppleLoginService.java @@ -3,6 +3,7 @@ import com.onnoff.onnoff.auth.UserContext; import com.onnoff.onnoff.auth.feignClient.client.AppleAuthClient; +import com.onnoff.onnoff.auth.feignClient.dto.apple.RevokeTokenReqeust; import com.onnoff.onnoff.auth.feignClient.dto.apple.TokenRequest; import com.onnoff.onnoff.auth.feignClient.dto.TokenResponse; import com.onnoff.onnoff.auth.service.tokenValidator.SocialTokenValidator; @@ -27,8 +28,6 @@ import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Date; -import java.util.HashMap; -import java.util.Map; @Service @RequiredArgsConstructor @@ -116,4 +115,15 @@ public void validate(String identityToken){ String cleanedIdentityToken = cleanToken(identityToken); validator.validate(cleanedIdentityToken, SocialType.APPLE); } + + public void revokeTokens(String refreshToken) { + String clientSecret = createClientSecret(); + MultiValueMap urlEncoded = RevokeTokenReqeust.builder() + .clientId(clientId) + .clientSecret(clientSecret) + .token(refreshToken) + .build().toUrlEncoded(); + appleAuthClient.revokeTokens(urlEncoded); + } + } diff --git a/src/main/java/com/onnoff/onnoff/auth/service/KakaoLoginService.java b/src/main/java/com/onnoff/onnoff/auth/service/KakaoLoginService.java index 7d3fa77..314fc14 100644 --- a/src/main/java/com/onnoff/onnoff/auth/service/KakaoLoginService.java +++ b/src/main/java/com/onnoff/onnoff/auth/service/KakaoLoginService.java @@ -6,12 +6,15 @@ import com.onnoff.onnoff.auth.feignClient.client.KakaoOauth2Client; import com.onnoff.onnoff.auth.feignClient.dto.TokenResponse; import com.onnoff.onnoff.auth.feignClient.dto.kakao.KakaoOauth2DTO; +import com.onnoff.onnoff.auth.feignClient.dto.kakao.UnlinkRequest; import com.onnoff.onnoff.auth.service.tokenValidator.SocialTokenValidator; import com.onnoff.onnoff.domain.user.enums.SocialType; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; +import org.springframework.util.MultiValueMap; @Service @@ -25,6 +28,8 @@ public class KakaoLoginService implements LoginService{ private String clientId; @Value("${kakao.redirect-uri}") private String redirectUri; + @Value("${kakao.admin-key}") + private String adminKey; /* 테스트 용으로 만든거, 실제로는 프론트에서 처리해서 액세스 토큰만 가져다 줌 */ @@ -41,9 +46,22 @@ public void validate(String idToken){ String cleanedAccessToken = cleanToken(idToken); validator.validate(cleanedAccessToken, SocialType.KAKAO); } - /* - 토큰으로 유저정보를 가져오는 메서드 - */ + + public void revokeTokens(String oauthId) { + MultiValueMap urlEncoded = UnlinkRequest.builder() + .targetIdType("user_id") + .targetId(oauthId) + .build() + .toUrlEncoded(); + adminKey = "KakaoAK " + adminKey; + log.info("adminkey = {}", adminKey); + ResponseEntity responseEntity = kakaoApiClient.unlink(adminKey, urlEncoded); + log.info("삭제된 회원 정보 = {}", responseEntity.getBody()); + } + + /* + 토큰으로 유저정보를 가져오는 메서드 + */ public KakaoOauth2DTO.UserInfoResponseDTO getUserInfo(String accessToken) throws JsonProcessingException { String cleanedAccessToken = cleanToken(accessToken); accessToken = "bearer " + cleanedAccessToken; diff --git a/src/main/java/com/onnoff/onnoff/domain/user/controller/UserController.java b/src/main/java/com/onnoff/onnoff/domain/user/controller/UserController.java index 024d86f..3eda6d0 100644 --- a/src/main/java/com/onnoff/onnoff/domain/user/controller/UserController.java +++ b/src/main/java/com/onnoff/onnoff/domain/user/controller/UserController.java @@ -37,6 +37,14 @@ public ApiResponse modifyUser(@RequestBody UserRe return ApiResponse.onSuccess(UserConverter.toUserDetailDTO(userService.modifyUser(modifyUserDTO))); } + //테스트용 + @PutMapping("/hard-delete") + @Operation(summary = "회원 완전 탈퇴 테스트 API",description = "30일 뒤에 자동 완전삭제 수동 테스트") + public ApiResponse hardDeleteTest(){ + userService.deleteInactiveUsersTest(); + return ApiResponse.onSuccess("삭제완"); + } + @PostMapping("/nickname") @Operation(summary = "닉네임 중복 체크 API") public ApiResponse checkNickname(@Valid @RequestBody UserRequestDTO.getNicknameDTO nicknameDTO){ diff --git a/src/main/java/com/onnoff/onnoff/domain/user/converter/UserConverter.java b/src/main/java/com/onnoff/onnoff/domain/user/converter/UserConverter.java index 5074078..a09d324 100644 --- a/src/main/java/com/onnoff/onnoff/domain/user/converter/UserConverter.java +++ b/src/main/java/com/onnoff/onnoff/domain/user/converter/UserConverter.java @@ -14,26 +14,20 @@ public class UserConverter { public static User toUser(KakaoOauth2DTO.UserInfoResponseDTO response, LoginRequestDTO.AdditionalInfo additionalInfo){ - String fieldOfWork = additionalInfo.getFieldOfWork(); - try{ - FieldOfWork.valueOf(fieldOfWork); - } - catch (IllegalArgumentException e){ - throw new GeneralException(ErrorStatus.INVALID_ENUM_VALUE); - } - + FieldOfWork fieldOfWork = FieldOfWork.fromValue(additionalInfo.getFieldOfWork()); ExperienceYear experienceYear = ExperienceYear.fromValue(additionalInfo.getExperienceYear()); return User.builder() .oauthId(response.getSub()) .email(response.getEmail()) .name(response.getNickname()) .socialType(SocialType.KAKAO) - .fieldOfWork(Enum.valueOf(FieldOfWork.class ,additionalInfo.getFieldOfWork() ) ) + .fieldOfWork(fieldOfWork) .job(additionalInfo.getJob()) .experienceYear(experienceYear) .build(); } public static User toUser(LoginRequestDTO.AppleTokenValidateDTO request, LoginRequestDTO.AdditionalInfo additionalInfo){ + FieldOfWork fieldOfWork = FieldOfWork.fromValue(additionalInfo.getFieldOfWork()); ExperienceYear experienceYear = ExperienceYear.fromValue(additionalInfo.getExperienceYear()); String fullName = request.getFullName().getFamilyName() + request.getFullName().getGivenName(); return User.builder() @@ -41,7 +35,7 @@ public static User toUser(LoginRequestDTO.AppleTokenValidateDTO request, LoginRe .email(request.getEmail()) .name(fullName) .socialType(SocialType.APPLE) - .fieldOfWork(Enum.valueOf(FieldOfWork.class ,additionalInfo.getFieldOfWork() ) ) + .fieldOfWork(fieldOfWork) .job(additionalInfo.getJob()) .experienceYear(experienceYear) .build(); diff --git a/src/main/java/com/onnoff/onnoff/domain/user/dto/EnumInquiryResponseDTO.java b/src/main/java/com/onnoff/onnoff/domain/user/dto/EnumInquiryResponseDTO.java index 830d50f..362cd11 100644 --- a/src/main/java/com/onnoff/onnoff/domain/user/dto/EnumInquiryResponseDTO.java +++ b/src/main/java/com/onnoff/onnoff/domain/user/dto/EnumInquiryResponseDTO.java @@ -12,7 +12,7 @@ public class EnumInquiryResponseDTO { public static class FieldOfWorkResponseDTO{ public static List getAllField() { return Arrays.stream(FieldOfWork.values()) - .map(Enum::name) + .map(FieldOfWork::getValue) .collect(Collectors.toList()); } } diff --git a/src/main/java/com/onnoff/onnoff/domain/user/enums/FieldOfWork.java b/src/main/java/com/onnoff/onnoff/domain/user/enums/FieldOfWork.java index 18a356c..e769733 100644 --- a/src/main/java/com/onnoff/onnoff/domain/user/enums/FieldOfWork.java +++ b/src/main/java/com/onnoff/onnoff/domain/user/enums/FieldOfWork.java @@ -1,15 +1,40 @@ package com.onnoff.onnoff.domain.user.enums; +import com.onnoff.onnoff.apiPayload.code.status.ErrorStatus; +import com.onnoff.onnoff.apiPayload.exception.GeneralException; import lombok.AllArgsConstructor; +import lombok.Getter; @AllArgsConstructor +@Getter public enum FieldOfWork { - 서비스업, 의료_제약_복지, 제조_화학, - 판매_유통, IT_웹_통신, 건설업, - 교육업, 미디어_디자인, 은행_금융업, - 기관_협회, 비즈니스_투자, 물류_무역업, - 법률_법집행기관, 방송_광고_엔터테인먼트, 여행_숙박_음식점업, - 부동산_임대업 + 서비스업("서비스업"), + 의료_제약_복지("의료•제약•복지"), + 제조_화학("제조•화학"), + 판매_유통("판매•유통"), + IT_웹_통신("IT•웹•통신"), + 건설업("건설업"), + 교육업("교육업"), + 미디어_디자인("미디어•디자인"), + 은행_금융업("은행•금융업"), + 기관_협회("기관•협회"), + 비즈니스_투자("비즈니스•투자"), + 물류_무역업("물류•무역업"), + 법률_법집행기관("법률•법집행기관"), + 방송_광고_엔터테인먼트("방송•광고•엔터테인먼트"), + 여행_숙박_음식점업("여행•숙박•음식점업"), + 부동산_임대업("부동산•임대업"); + + private final String value; + + public static FieldOfWork fromValue(String value) { + for (FieldOfWork fieldOfWork : FieldOfWork.values()) { + if (fieldOfWork.getValue().equals(value)) { + return fieldOfWork; + } + } + throw new GeneralException(ErrorStatus.INVALID_ENUM_VALUE); + } } diff --git a/src/main/java/com/onnoff/onnoff/domain/user/enums/SocialType.java b/src/main/java/com/onnoff/onnoff/domain/user/enums/SocialType.java index c2fe68b..9668375 100644 --- a/src/main/java/com/onnoff/onnoff/domain/user/enums/SocialType.java +++ b/src/main/java/com/onnoff/onnoff/domain/user/enums/SocialType.java @@ -1,5 +1,9 @@ package com.onnoff.onnoff.domain.user.enums; public enum SocialType { - KAKAO, APPLE + KAKAO, APPLE; + + public static boolean isApple(SocialType socialType){ + return socialType.equals(SocialType.APPLE); + } } diff --git a/src/main/java/com/onnoff/onnoff/domain/user/service/UserService.java b/src/main/java/com/onnoff/onnoff/domain/user/service/UserService.java index 1830204..47d55a8 100644 --- a/src/main/java/com/onnoff/onnoff/domain/user/service/UserService.java +++ b/src/main/java/com/onnoff/onnoff/domain/user/service/UserService.java @@ -19,5 +19,9 @@ public interface UserService { public User getUserByOauthId(String oauthId); public User withdrawUser(); + + public void deleteInactiveUsers(); + + public void deleteInactiveUsersTest(); public User modifyUser(UserRequestDTO.ModifyUserDTO modifyUserDTO); } diff --git a/src/main/java/com/onnoff/onnoff/domain/user/service/UserServiceImpl.java b/src/main/java/com/onnoff/onnoff/domain/user/service/UserServiceImpl.java index ecc1f25..c55256f 100644 --- a/src/main/java/com/onnoff/onnoff/domain/user/service/UserServiceImpl.java +++ b/src/main/java/com/onnoff/onnoff/domain/user/service/UserServiceImpl.java @@ -3,8 +3,11 @@ import com.onnoff.onnoff.apiPayload.code.status.ErrorStatus; import com.onnoff.onnoff.apiPayload.exception.GeneralException; import com.onnoff.onnoff.auth.UserContext; +import com.onnoff.onnoff.auth.service.AppleLoginService; +import com.onnoff.onnoff.auth.service.KakaoLoginService; import com.onnoff.onnoff.domain.user.User; import com.onnoff.onnoff.domain.user.dto.UserRequestDTO; +import com.onnoff.onnoff.domain.user.enums.SocialType; import com.onnoff.onnoff.domain.user.enums.Status; import com.onnoff.onnoff.domain.user.repository.UserRepository; import lombok.RequiredArgsConstructor; @@ -19,6 +22,10 @@ @RequiredArgsConstructor public class UserServiceImpl implements UserService{ private final UserRepository userRepository; + private final AppleLoginService appleLoginService; + private final KakaoLoginService kakaoLoginService; + + @Transactional @Override public User create(User user) { @@ -67,7 +74,6 @@ public User getUserByOauthId(String oauthId) { public User withdrawUser(){ User user = UserContext.getUser(); user.setUserStatusInactive(); - userRepository.save(user); return user; } @@ -86,5 +92,26 @@ public void deleteInactiveUsers() { LocalDateTime oneMonthAgo = LocalDateTime.now().minusMonths(1); List inactiveUsers = userRepository.findByStatusAndInactiveDateBefore(Status.INACTIVE, oneMonthAgo); inactiveUsers.forEach(userRepository::delete); + inactiveUsers.forEach(this::disconnectApp); } + @Transactional + public void deleteInactiveUsersTest() { + LocalDateTime oneMonthAgo = LocalDateTime.now(); + List inactiveUsers = userRepository.findByStatusAndInactiveDateBefore(Status.INACTIVE, oneMonthAgo); + inactiveUsers.forEach(userRepository::delete); + inactiveUsers.forEach(this::disconnectApp); + } + // 유저 소셜계정 앱 연동 해지 + private void disconnectApp(User user){ + SocialType socialType = user.getSocialType(); + if(SocialType.isApple(socialType)) { + String appleRefreshToken = user.getAppleRefreshToken(); + appleLoginService.revokeTokens(appleRefreshToken); + } + else { + String oauthId = user.getOauthId(); + kakaoLoginService.revokeTokens(oauthId); + } + } + } diff --git a/src/test/java/com/onnoff/onnoff/domain/user/service/UserServiceImplTest.java b/src/test/java/com/onnoff/onnoff/domain/user/service/UserServiceImplTest.java index 76268a5..2585534 100644 --- a/src/test/java/com/onnoff/onnoff/domain/user/service/UserServiceImplTest.java +++ b/src/test/java/com/onnoff/onnoff/domain/user/service/UserServiceImplTest.java @@ -8,12 +8,14 @@ import org.springframework.boot.test.context.SpringBootTest; - @SpringBootTest @Transactional class UserServiceImplTest { + private final UserService userService; - @Autowired UserService userService; + public UserServiceImplTest(@Autowired UserService userService) { + this.userService = userService; + } @Test void 생성_및_조회() { User user = User.builder().name("우성").nickname("우스").build(); @@ -24,5 +26,4 @@ class UserServiceImplTest { Assertions.assertThat(user.getName()).isEqualTo(findUser.getName()); } - } \ No newline at end of file