From 002cca969701e63d087c8286ca45f1edc2c5d7b8 Mon Sep 17 00:00:00 2001 From: Rimi Date: Wed, 26 Jun 2024 16:22:59 +0900 Subject: [PATCH 01/11] =?UTF-8?q?:recycle:=20[refactor]=20@RequestBody=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=ED=95=98=EA=B8=B0,=20login,=20join=20?= =?UTF-8?q?=EB=92=A4=EC=97=90=20local=20=EB=B9=BC=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/gamegoo/config/SecurityConfig.java | 4 ++-- .../com/gamegoo/controller/member/DeleteController.java | 2 +- .../java/com/gamegoo/controller/member/EmailController.java | 3 ++- .../java/com/gamegoo/controller/member/JoinController.java | 6 ++++-- .../controller/member/MemberGameStyleController.java | 3 ++- .../com/gamegoo/controller/member/PasswordController.java | 5 +++-- .../com/gamegoo/controller/member/PositionController.java | 3 ++- .../gamegoo/controller/member/ProfileImageController.java | 3 ++- src/main/java/com/gamegoo/security/LoginFilter.java | 4 +++- 9 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/gamegoo/config/SecurityConfig.java b/src/main/java/com/gamegoo/config/SecurityConfig.java index f1a74afe..7519832a 100644 --- a/src/main/java/com/gamegoo/config/SecurityConfig.java +++ b/src/main/java/com/gamegoo/config/SecurityConfig.java @@ -37,7 +37,7 @@ public AuthenticationManager authenticationManager(AuthenticationConfiguration c @Bean public JWTFilter jwtFilter() { - List excludedPaths = Arrays.asList("/api/member/join/local", "/api/member/login/local", "/api/member/email"); + List excludedPaths = Arrays.asList("/api/member/join", "/api/member/login", "/api/member/email"); return new JWTFilter(jwtUtil, excludedPaths); } @@ -53,7 +53,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .formLogin(AbstractHttpConfigurer::disable) .httpBasic(AbstractHttpConfigurer::disable) .authorizeHttpRequests((auth) -> auth - .antMatchers("/api/member/join/local", "/api/member/login/local", "/api/member/email").permitAll() + .antMatchers("/api/member/join", "/api/member/login", "/api/member/email").permitAll() .anyRequest().authenticated()) .addFilterAt(new LoginFilter(authenticationManager(authenticationConfiguration), jwtUtil), UsernamePasswordAuthenticationFilter.class) .addFilterBefore(jwtFilter(), LoginFilter.class) diff --git a/src/main/java/com/gamegoo/controller/member/DeleteController.java b/src/main/java/com/gamegoo/controller/member/DeleteController.java index a140bb02..e379b617 100644 --- a/src/main/java/com/gamegoo/controller/member/DeleteController.java +++ b/src/main/java/com/gamegoo/controller/member/DeleteController.java @@ -21,7 +21,7 @@ public class DeleteController { private final DeleteService deleteService; @DeleteMapping("") - @Operation(summary = "회원 탈퇴 API 입니다.", description = "API for blind Member") + @Operation(summary = "회원 탈퇴 API 입니다.", description = "API for Member") public ApiResponse blindMember() { Long userId = SecurityUtil.getCurrentUserId(); //헤더에 있는 jwt 토큰에서 id를 가져오는 코드 try { diff --git a/src/main/java/com/gamegoo/controller/member/EmailController.java b/src/main/java/com/gamegoo/controller/member/EmailController.java index d31813b3..e805e73c 100644 --- a/src/main/java/com/gamegoo/controller/member/EmailController.java +++ b/src/main/java/com/gamegoo/controller/member/EmailController.java @@ -7,6 +7,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -21,7 +22,7 @@ public class EmailController { @PostMapping("/email") @Operation(summary = "이메일 인증코드 전송 API 입니다.", description = "API for email verification") - public ApiResponse verifyEmail(EmailDTO emailDTO) throws IOException { + public ApiResponse verifyEmail(@RequestBody EmailDTO emailDTO) throws IOException { String emailAddress = emailDTO.getEmail_address(); String code = emailService.verifyEmail(emailAddress); return ApiResponse.onSuccess(code); diff --git a/src/main/java/com/gamegoo/controller/member/JoinController.java b/src/main/java/com/gamegoo/controller/member/JoinController.java index 9d83b964..876652b5 100644 --- a/src/main/java/com/gamegoo/controller/member/JoinController.java +++ b/src/main/java/com/gamegoo/controller/member/JoinController.java @@ -7,6 +7,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -17,9 +18,10 @@ public class JoinController { private final JoinService joinService; - @PostMapping("/join/local") + @PostMapping("/join") @Operation(summary = "회원가입 API 입니다.", description = "API for join") - public ApiResponse joinMember(JoinDTO joinDTO) { + public ApiResponse joinMember(@RequestBody JoinDTO joinDTO) { + System.out.println(joinDTO.getPassword()); joinService.JoinMember(joinDTO); return ApiResponse.onSuccess(null); } diff --git a/src/main/java/com/gamegoo/controller/member/MemberGameStyleController.java b/src/main/java/com/gamegoo/controller/member/MemberGameStyleController.java index ad1c795c..461636fa 100644 --- a/src/main/java/com/gamegoo/controller/member/MemberGameStyleController.java +++ b/src/main/java/com/gamegoo/controller/member/MemberGameStyleController.java @@ -7,6 +7,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -21,7 +22,7 @@ public class MemberGameStyleController { @PutMapping("/gamestyle") @Operation(summary = "gamestyle 추가 및 수정 API 입니다.", description = "API for Gamestyle addition and modification ") - public ApiResponse addGameStyle(GameStyleDTO gameStyleDTO) throws IOException { + public ApiResponse addGameStyle(@RequestBody GameStyleDTO gameStyleDTO) throws IOException { memberGameStyleService.addMemberGameStyles(gameStyleDTO.getGamestyle()); return ApiResponse.onSuccess(null); } diff --git a/src/main/java/com/gamegoo/controller/member/PasswordController.java b/src/main/java/com/gamegoo/controller/member/PasswordController.java index 54f96f34..10b5b138 100644 --- a/src/main/java/com/gamegoo/controller/member/PasswordController.java +++ b/src/main/java/com/gamegoo/controller/member/PasswordController.java @@ -8,6 +8,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -20,7 +21,7 @@ public class PasswordController { @PostMapping("/check") @Operation(summary = "비밀번호 확인 API 입니다.", description = "API for checking password") - public ApiResponse checkPassword(PasswordDTO passwordDTO) { + public ApiResponse checkPassword(@RequestBody PasswordDTO passwordDTO) { Long currentUserId = SecurityUtil.getCurrentUserId(); //헤더에 있는 jwt 토큰에서 id를 가져오는 코드 boolean isPasswordValid = passwordService.checkPasswordById(currentUserId, passwordDTO.getPassword()); //request body에 있는 password와 currentUserId를 전달 @@ -33,7 +34,7 @@ public ApiResponse checkPassword(PasswordDTO passwordDTO) { @PostMapping("/reset") @Operation(summary = "비밀번호 재설정 API 입니다.", description = "API for reseting password") - public ApiResponse resetPassword(PasswordDTO passwordDTO) { + public ApiResponse resetPassword(@RequestBody PasswordDTO passwordDTO) { Long currentUserId = SecurityUtil.getCurrentUserId(); passwordService.updatePassword(currentUserId, passwordDTO.getPassword()); diff --git a/src/main/java/com/gamegoo/controller/member/PositionController.java b/src/main/java/com/gamegoo/controller/member/PositionController.java index 40c89216..711972ff 100644 --- a/src/main/java/com/gamegoo/controller/member/PositionController.java +++ b/src/main/java/com/gamegoo/controller/member/PositionController.java @@ -7,6 +7,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -21,7 +22,7 @@ public class PositionController { @PutMapping("/position") @Operation(summary = "주/부 포지션 수정 API 입니다.", description = "API for Main/Sub Position Modification") - public ApiResponse modifyPosition(PositionDTO positionDTO) throws IOException { + public ApiResponse modifyPosition(@RequestBody PositionDTO positionDTO) throws IOException { int mainP = positionDTO.getMainP(); int subP = positionDTO.getSubP(); positionService.modifyPosition(mainP, subP); diff --git a/src/main/java/com/gamegoo/controller/member/ProfileImageController.java b/src/main/java/com/gamegoo/controller/member/ProfileImageController.java index dc2bfdbb..515637e9 100644 --- a/src/main/java/com/gamegoo/controller/member/ProfileImageController.java +++ b/src/main/java/com/gamegoo/controller/member/ProfileImageController.java @@ -7,6 +7,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -21,7 +22,7 @@ public class ProfileImageController { @PutMapping("/profile_image") @Operation(summary = "프로필 이미지 수정 API 입니다.", description = "API for Profile Image Modification") - public ApiResponse modifyPosition(ProfileImageDTO profileImageDTO) throws IOException { + public ApiResponse modifyPosition(@RequestBody ProfileImageDTO profileImageDTO) throws IOException { String profileImage = profileImageDTO.getProfile_image(); profileImageService.modifyPosition(profileImage); return ApiResponse.onSuccess(null); diff --git a/src/main/java/com/gamegoo/security/LoginFilter.java b/src/main/java/com/gamegoo/security/LoginFilter.java index d261f047..9930b625 100644 --- a/src/main/java/com/gamegoo/security/LoginFilter.java +++ b/src/main/java/com/gamegoo/security/LoginFilter.java @@ -10,6 +10,7 @@ import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.FilterChain; import javax.servlet.http.HttpServletRequest; @@ -17,6 +18,7 @@ import java.io.IOException; import java.util.Objects; +@ResponseBody // 로그인 시 실행되는 로그인 필터 public class LoginFilter extends UsernamePasswordAuthenticationFilter { private final AuthenticationManager authenticationManager; @@ -25,7 +27,7 @@ public class LoginFilter extends UsernamePasswordAuthenticationFilter { public LoginFilter(AuthenticationManager authenticationManager, JWTUtil jwtUtil) { this.authenticationManager = authenticationManager; this.jwtUtil = jwtUtil; - this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/api/member/login/local", "POST")); + this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/api/member/login", "POST")); this.setUsernameParameter("email"); this.setPasswordParameter("password"); } From 5a0cad4b70d488e88ec3444778e2f846dc5834ad Mon Sep 17 00:00:00 2001 From: Rimi Date: Fri, 28 Jun 2024 08:33:20 +0900 Subject: [PATCH 02/11] =?UTF-8?q?:bug:=20[fix]=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20=ED=95=84=ED=84=B0=20=EC=98=88=EC=99=B8=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=EC=88=98=EC=A0=95=20&=20=EC=84=B1=EA=B3=B5?= =?UTF-8?q?=ED=96=88=EC=9D=84=20=EA=B2=BD=EC=9A=B0=20result=EC=97=90=20?= =?UTF-8?q?=ED=86=A0=ED=81=B0=20=ED=8F=AC=ED=95=A8=ED=95=B4=EC=84=9C=20?= =?UTF-8?q?=EB=B3=B4=EB=82=B4=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/CustomUserException.java | 9 ++++ .../exception/handler/MemberHandler.java | 10 ++++ .../MemberNotFoundExceptionHandler.java | 14 ----- .../UserDeactivatedExceptionHandler.java | 14 ----- .../com/gamegoo/config/SecurityConfig.java | 11 ++-- .../controller/member/DeleteController.java | 7 +-- .../controller/member/JoinController.java | 1 + src/main/java/com/gamegoo/domain/Member.java | 2 +- src/main/java/com/gamegoo/jwt/JWTFilter.java | 53 ++++++------------- .../repository/member/MemberRepository.java | 1 + .../security/CustomUserDetailService.java | 44 +++++++++++++++ ...berDetails.java => CustomUserDetails.java} | 16 ++---- .../com/gamegoo/security/LoginFilter.java | 51 ++++++++++-------- .../com/gamegoo/security/SecurityUtil.java | 2 +- .../member/CustomMemberDetailService.java | 48 ----------------- .../gamegoo/service/member/DeleteService.java | 4 +- .../gamegoo/service/member/JoinService.java | 1 - .../service/member/PasswordService.java | 4 +- 18 files changed, 132 insertions(+), 160 deletions(-) create mode 100644 src/main/java/com/gamegoo/apiPayload/exception/CustomUserException.java create mode 100644 src/main/java/com/gamegoo/apiPayload/exception/handler/MemberHandler.java delete mode 100644 src/main/java/com/gamegoo/apiPayload/exception/handler/MemberNotFoundExceptionHandler.java delete mode 100644 src/main/java/com/gamegoo/apiPayload/exception/handler/UserDeactivatedExceptionHandler.java create mode 100644 src/main/java/com/gamegoo/security/CustomUserDetailService.java rename src/main/java/com/gamegoo/security/{CustomMemberDetails.java => CustomUserDetails.java} (68%) delete mode 100644 src/main/java/com/gamegoo/service/member/CustomMemberDetailService.java diff --git a/src/main/java/com/gamegoo/apiPayload/exception/CustomUserException.java b/src/main/java/com/gamegoo/apiPayload/exception/CustomUserException.java new file mode 100644 index 00000000..6e90fa76 --- /dev/null +++ b/src/main/java/com/gamegoo/apiPayload/exception/CustomUserException.java @@ -0,0 +1,9 @@ +package com.gamegoo.apiPayload.exception; + +import org.springframework.security.core.AuthenticationException; + +public class CustomUserException extends AuthenticationException { + public CustomUserException(String msg) { + super(msg); + } +} diff --git a/src/main/java/com/gamegoo/apiPayload/exception/handler/MemberHandler.java b/src/main/java/com/gamegoo/apiPayload/exception/handler/MemberHandler.java new file mode 100644 index 00000000..b1be9fcf --- /dev/null +++ b/src/main/java/com/gamegoo/apiPayload/exception/handler/MemberHandler.java @@ -0,0 +1,10 @@ +package com.gamegoo.apiPayload.exception.handler; + +import com.gamegoo.apiPayload.code.BaseErrorCode; +import com.gamegoo.apiPayload.exception.GeneralException; + +public class MemberHandler extends GeneralException { + public MemberHandler(BaseErrorCode code) { + super(code); + } +} diff --git a/src/main/java/com/gamegoo/apiPayload/exception/handler/MemberNotFoundExceptionHandler.java b/src/main/java/com/gamegoo/apiPayload/exception/handler/MemberNotFoundExceptionHandler.java deleted file mode 100644 index 2566200b..00000000 --- a/src/main/java/com/gamegoo/apiPayload/exception/handler/MemberNotFoundExceptionHandler.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.gamegoo.apiPayload.exception.handler; - - -import com.gamegoo.apiPayload.code.status.ErrorStatus; -import lombok.Getter; -import org.springframework.security.core.AuthenticationException; - -@Getter -public class MemberNotFoundExceptionHandler extends AuthenticationException { - public MemberNotFoundExceptionHandler(ErrorStatus errorStatus) { - super(errorStatus.getMessage()); - } - -} diff --git a/src/main/java/com/gamegoo/apiPayload/exception/handler/UserDeactivatedExceptionHandler.java b/src/main/java/com/gamegoo/apiPayload/exception/handler/UserDeactivatedExceptionHandler.java deleted file mode 100644 index f4a8fefd..00000000 --- a/src/main/java/com/gamegoo/apiPayload/exception/handler/UserDeactivatedExceptionHandler.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.gamegoo.apiPayload.exception.handler; - - -import com.gamegoo.apiPayload.code.status.ErrorStatus; -import lombok.Getter; -import org.springframework.security.core.AuthenticationException; - -@Getter -public class UserDeactivatedExceptionHandler extends AuthenticationException { - - public UserDeactivatedExceptionHandler(ErrorStatus errorStatus) { - super(errorStatus.getMessage()); - } -} diff --git a/src/main/java/com/gamegoo/config/SecurityConfig.java b/src/main/java/com/gamegoo/config/SecurityConfig.java index 7519832a..051125f5 100644 --- a/src/main/java/com/gamegoo/config/SecurityConfig.java +++ b/src/main/java/com/gamegoo/config/SecurityConfig.java @@ -2,6 +2,7 @@ import com.gamegoo.jwt.JWTFilter; import com.gamegoo.jwt.JWTUtil; +import com.gamegoo.security.CustomUserDetailService; import com.gamegoo.security.LoginFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -18,16 +19,17 @@ import java.util.Arrays; import java.util.List; - @Configuration @EnableWebSecurity public class SecurityConfig { private final AuthenticationConfiguration authenticationConfiguration; private final JWTUtil jwtUtil; + private final CustomUserDetailService customUserDetailService; - public SecurityConfig(AuthenticationConfiguration authenticationConfiguration, JWTUtil jwtUtil) { + public SecurityConfig(AuthenticationConfiguration authenticationConfiguration, JWTUtil jwtUtil, CustomUserDetailService customUserDetailService) { this.authenticationConfiguration = authenticationConfiguration; this.jwtUtil = jwtUtil; + this.customUserDetailService = customUserDetailService; } @Bean @@ -38,7 +40,7 @@ public AuthenticationManager authenticationManager(AuthenticationConfiguration c @Bean public JWTFilter jwtFilter() { List excludedPaths = Arrays.asList("/api/member/join", "/api/member/login", "/api/member/email"); - return new JWTFilter(jwtUtil, excludedPaths); + return new JWTFilter(jwtUtil, excludedPaths, customUserDetailService); } @Bean @@ -49,12 +51,15 @@ public BCryptPasswordEncoder bCryptPasswordEncoder() { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http + .csrf(AbstractHttpConfigurer::disable) .formLogin(AbstractHttpConfigurer::disable) .httpBasic(AbstractHttpConfigurer::disable) + .authorizeHttpRequests((auth) -> auth .antMatchers("/api/member/join", "/api/member/login", "/api/member/email").permitAll() .anyRequest().authenticated()) + .addFilterAt(new LoginFilter(authenticationManager(authenticationConfiguration), jwtUtil), UsernamePasswordAuthenticationFilter.class) .addFilterBefore(jwtFilter(), LoginFilter.class) .sessionManagement((session) -> session diff --git a/src/main/java/com/gamegoo/controller/member/DeleteController.java b/src/main/java/com/gamegoo/controller/member/DeleteController.java index e379b617..954bc3a6 100644 --- a/src/main/java/com/gamegoo/controller/member/DeleteController.java +++ b/src/main/java/com/gamegoo/controller/member/DeleteController.java @@ -2,7 +2,7 @@ import com.gamegoo.apiPayload.ApiResponse; import com.gamegoo.apiPayload.code.status.ErrorStatus; -import com.gamegoo.apiPayload.exception.handler.UserDeactivatedExceptionHandler; +import com.gamegoo.apiPayload.exception.handler.MemberHandler; import com.gamegoo.security.SecurityUtil; import com.gamegoo.service.member.DeleteService; import io.swagger.v3.oas.annotations.Operation; @@ -27,11 +27,8 @@ public ApiResponse blindMember() { try { deleteService.deleteMember(userId); return ApiResponse.onSuccess(null); - } catch (UserDeactivatedExceptionHandler e) { - return ApiResponse.onFailure(ErrorStatus.MEMBER_NOT_FOUND.getCode(), e.getMessage(), null); } catch (Exception e) { - log.error("Unexpected error occurred during member deletion", e); - return ApiResponse.onFailure(ErrorStatus.TEMP_EXCEPTION.getCode(), ErrorStatus.TEMP_EXCEPTION.getMessage(), null); + throw new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND); } } diff --git a/src/main/java/com/gamegoo/controller/member/JoinController.java b/src/main/java/com/gamegoo/controller/member/JoinController.java index 876652b5..6490f375 100644 --- a/src/main/java/com/gamegoo/controller/member/JoinController.java +++ b/src/main/java/com/gamegoo/controller/member/JoinController.java @@ -22,6 +22,7 @@ public class JoinController { @Operation(summary = "회원가입 API 입니다.", description = "API for join") public ApiResponse joinMember(@RequestBody JoinDTO joinDTO) { System.out.println(joinDTO.getPassword()); + System.out.println(joinDTO.getEmail()); joinService.JoinMember(joinDTO); return ApiResponse.onSuccess(null); } diff --git a/src/main/java/com/gamegoo/domain/Member.java b/src/main/java/com/gamegoo/domain/Member.java index b841831f..af5d8e2c 100644 --- a/src/main/java/com/gamegoo/domain/Member.java +++ b/src/main/java/com/gamegoo/domain/Member.java @@ -19,7 +19,7 @@ @Getter @Setter @Builder -@NoArgsConstructor(access = AccessLevel.PUBLIC) +@NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor public class Member extends BaseDateTimeEntity { @Id diff --git a/src/main/java/com/gamegoo/jwt/JWTFilter.java b/src/main/java/com/gamegoo/jwt/JWTFilter.java index b9a2e0ed..b87b4ae8 100644 --- a/src/main/java/com/gamegoo/jwt/JWTFilter.java +++ b/src/main/java/com/gamegoo/jwt/JWTFilter.java @@ -1,12 +1,10 @@ package com.gamegoo.jwt; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.gamegoo.apiPayload.ApiResponse; import com.gamegoo.apiPayload.code.status.ErrorStatus; -import com.gamegoo.domain.Member; -import com.gamegoo.security.CustomMemberDetails; -import io.jsonwebtoken.ExpiredJwtException; -import io.jsonwebtoken.JwtException; +import com.gamegoo.apiPayload.exception.handler.MemberHandler; +import com.gamegoo.security.CustomUserDetailService; +import com.gamegoo.security.CustomUserDetails; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; @@ -25,33 +23,32 @@ public class JWTFilter extends OncePerRequestFilter { private final JWTUtil jwtUtil; private final List excludedPaths; - public JWTFilter(JWTUtil jwtUtil, List excludedPaths) { + private final CustomUserDetailService customUserDetailService; + + @Autowired + public JWTFilter(JWTUtil jwtUtil, List excludedPaths, CustomUserDetailService customUserDetailService) { this.jwtUtil = jwtUtil; this.excludedPaths = excludedPaths; + this.customUserDetailService = customUserDetailService; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String requestURI = request.getRequestURI(); - // Exclude paths from JWT filter + // JWT Filter를 사용하지 않는 Path는 제외 if (excludedPaths.stream().anyMatch(requestURI::startsWith)) { filterChain.doFilter(request, response); return; } - // request에서 Authorization 헤더를 찾음 + // request 헤더에서 Authorization 헤더를 찾음 String authorization = request.getHeader("Authorization"); // Authorization 헤더 검증 if (authorization == null || !authorization.startsWith("Bearer ")) { - System.out.println("token null"); - setErrorResponse(response, ErrorStatus.INVALID_TOKEN); - filterChain.doFilter(request, response); - - //조건이 해당되면 메소드 종료 (필수) - return; + throw new MemberHandler(ErrorStatus.INVALID_TOKEN); } System.out.println("authorization now"); @@ -62,43 +59,27 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse try { // 토큰 소멸 시간 검증 if (jwtUtil.isExpired(token)) { - setErrorResponse(response, ErrorStatus.TOKEN_EXPIRED); - return; // 더 이상 진행하지 않음 + throw new MemberHandler(ErrorStatus.TOKEN_EXPIRED); } // jwt 토큰에서 id 획득 Long id = jwtUtil.getId(token); - // Member를 생성하여 값 set - Member member = new Member(); - member.setId(id); // UserDetails에 회원 정보 객체 담기 - CustomMemberDetails customMemberDetails = new CustomMemberDetails(member); + CustomUserDetails customUserDetails = (CustomUserDetails) customUserDetailService.loadUserById(id); // 스프링 시큐리티 인증 토큰 생성 - Authentication authToken = new UsernamePasswordAuthenticationToken(customMemberDetails, null, customMemberDetails.getAuthorities()); + Authentication authToken = new UsernamePasswordAuthenticationToken(customUserDetails, null, customUserDetails.getAuthorities()); // 세션에 사용자 등록 SecurityContextHolder.getContext().setAuthentication(authToken); filterChain.doFilter(request, response); - } catch (ExpiredJwtException e) { - setErrorResponse(response, ErrorStatus.TOKEN_EXPIRED); - } catch (JwtException e) { - setErrorResponse(response, ErrorStatus.INVALID_TOKEN); + } catch (Exception e) { - setErrorResponse(response, ErrorStatus._INTERNAL_SERVER_ERROR); + throw new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND); } } - private void setErrorResponse(HttpServletResponse response, ErrorStatus errorStatus) throws IOException { - ApiResponse apiResponse = ApiResponse.onFailure(errorStatus.getCode(), errorStatus.getMessage(), null); - - response.setStatus(errorStatus.getHttpStatus().value()); - response.setContentType("application/json"); - response.setCharacterEncoding("UTF-8"); - new ObjectMapper().writeValue(response.getWriter(), apiResponse); - - } } diff --git a/src/main/java/com/gamegoo/repository/member/MemberRepository.java b/src/main/java/com/gamegoo/repository/member/MemberRepository.java index adf73cd9..3bfe4d7f 100644 --- a/src/main/java/com/gamegoo/repository/member/MemberRepository.java +++ b/src/main/java/com/gamegoo/repository/member/MemberRepository.java @@ -9,4 +9,5 @@ public interface MemberRepository extends JpaRepository { Optional findByEmail(String email); Optional findById(Long id); + } diff --git a/src/main/java/com/gamegoo/security/CustomUserDetailService.java b/src/main/java/com/gamegoo/security/CustomUserDetailService.java new file mode 100644 index 00000000..9da10c0c --- /dev/null +++ b/src/main/java/com/gamegoo/security/CustomUserDetailService.java @@ -0,0 +1,44 @@ +package com.gamegoo.security; + +import com.gamegoo.apiPayload.code.status.ErrorStatus; +import com.gamegoo.apiPayload.exception.CustomUserException; +import com.gamegoo.apiPayload.exception.handler.MemberHandler; +import com.gamegoo.domain.Member; +import com.gamegoo.repository.member.MemberRepository; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +// 로그인 DB 로직 +@Service +public class CustomUserDetailService implements UserDetailsService { + private final MemberRepository memberRepository; + + public CustomUserDetailService(MemberRepository memberRepository) { + + this.memberRepository = memberRepository; + } + + @Override + public UserDetails loadUserByUsername(String email) { + return memberRepository.findByEmail(email) + .map(member -> { + if (member.getBlind()) { + throw new CustomUserException("해당 사용자는 탈퇴한 사용자입니다."); + } + return new CustomUserDetails(member); + }) + .orElseThrow(() -> new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND)); + } + + public UserDetails loadUserById(Long id) throws UsernameNotFoundException { + Member member = memberRepository.findById(id) + .filter(m -> !m.getBlind()) + .orElseThrow(() -> new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND)); + return new CustomUserDetails(member); + } + + +} + diff --git a/src/main/java/com/gamegoo/security/CustomMemberDetails.java b/src/main/java/com/gamegoo/security/CustomUserDetails.java similarity index 68% rename from src/main/java/com/gamegoo/security/CustomMemberDetails.java rename to src/main/java/com/gamegoo/security/CustomUserDetails.java index 957b2cd4..0cd51d21 100644 --- a/src/main/java/com/gamegoo/security/CustomMemberDetails.java +++ b/src/main/java/com/gamegoo/security/CustomUserDetails.java @@ -8,10 +8,10 @@ import java.util.Collection; // UserDetails 오버라이딩해서 Spring Security의 Login Filter에 사용하는 클래스 -public class CustomMemberDetails implements UserDetails { +public class CustomUserDetails implements UserDetails { private final Member member; - public CustomMemberDetails(Member member) { + public CustomUserDetails(Member member) { this.member = member; } @@ -21,15 +21,9 @@ public Collection getAuthorities() { Collection collection = new ArrayList<>(); - collection.add(new GrantedAuthority() { - - // 현 시점에서 여러 사용자의 권한을 구별할 필요가 없기 때문에 "USER"라는 권한으로 통일 - // 이후 사용자의 권한을 구별할 필요가 있을 경우 DB에 role column 생성 후 member.getRole() 메소드로 가져오기 - @Override - public String getAuthority() { - return "USER"; - } - }); + // 현 시점에서 여러 사용자의 권한을 구별할 필요가 없기 때문에 "USER"라는 권한으로 통일 +// 이후 사용자의 권한을 구별할 필요가 있을 경우 DB에 role column 생성 후 member.getRole() 메소드로 가져오기 + collection.add((GrantedAuthority) () -> "USER"); return collection; } diff --git a/src/main/java/com/gamegoo/security/LoginFilter.java b/src/main/java/com/gamegoo/security/LoginFilter.java index 9930b625..f2733861 100644 --- a/src/main/java/com/gamegoo/security/LoginFilter.java +++ b/src/main/java/com/gamegoo/security/LoginFilter.java @@ -5,6 +5,7 @@ import com.gamegoo.apiPayload.code.status.ErrorStatus; import com.gamegoo.jwt.JWTUtil; import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.InternalAuthenticationServiceException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; @@ -34,22 +35,21 @@ public LoginFilter(AuthenticationManager authenticationManager, JWTUtil jwtUtil) @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { - - //클라이언트 요청에서 username, password 추출 + // 클라이언트 요청에서 username, password 추출 String email = obtainUsername(request); String password = obtainPassword(request); - //스프링 시큐리티에서 username과 password를 검증하기 위해서는 token에 담아야 함 + // 스프링 시큐리티에서 username과 password를 검증하기 위해서는 token에 담아야 함 UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(email, password, null); - //token에 담은 검증을 위한 AuthenticationManager로 전달 + // token에 담은 검증을 위한 AuthenticationManager로 전달 return authenticationManager.authenticate(authToken); } - //로그인 성공시 실행하는 메소드 (JWT 발급) + // 로그인 성공시 실행하는 메소드 (JWT 발급) @Override protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) throws IOException { - CustomMemberDetails customUserDetails = (CustomMemberDetails) authentication.getPrincipal(); + CustomUserDetails customUserDetails = (CustomUserDetails) authentication.getPrincipal(); // 사용자 id 불러오기 Long id = customUserDetails.getId(); @@ -60,36 +60,43 @@ protected void successfulAuthentication(HttpServletRequest request, HttpServletR // 헤더에 추가 response.addHeader("Authorization", "Bearer " + token); + // 바디에 추가 + + // 성공 응답 생성 - ApiResponse apiResponse = ApiResponse.onSuccess(null); + ApiResponse apiResponse = ApiResponse.onSuccess(token); // 응답 설정 response.setStatus(HttpServletResponse.SC_OK); - response.setContentType("application/json"); - response.setCharacterEncoding("UTF-8"); - new ObjectMapper().writeValue(response.getWriter(), apiResponse); + apiResponse(response, apiResponse); } - //로그인 실패시 실행하는 메소드 + // 로그인 실패시 실행하는 메소드 @Override protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException { - ErrorStatus errorStatus; - - if (Objects.equals(failed.getMessage(), "해당 사용자는 탈퇴한 사용자입니다.")) { - errorStatus = ErrorStatus.USER_DEACTIVATED; - } else if (Objects.equals(failed.getMessage(), "해당 사용자를 찾을 수 없습니다.")) { - errorStatus = ErrorStatus.MEMBER_NOT_FOUND; - } else if (Objects.equals(failed.getMessage(), "자격 증명에 실패하였습니다.")) { - errorStatus = ErrorStatus.PASSWORD_INVALID; - } else { - errorStatus = ErrorStatus._UNAUTHORIZED; - } + ErrorStatus errorStatus = getErrorStatus(failed); ApiResponse apiResponse = ApiResponse.onFailure(errorStatus.getCode(), errorStatus.getMessage(), null); response.setStatus(errorStatus.getHttpStatus().value()); + apiResponse(response, apiResponse); + } + + private static void apiResponse(HttpServletResponse response, ApiResponse apiResponse) throws IOException { response.setContentType("application/json"); response.setCharacterEncoding("UTF-8"); new ObjectMapper().writeValue(response.getWriter(), apiResponse); + } + + private static ErrorStatus getErrorStatus(AuthenticationException failed) { + if (Objects.equals(failed.getMessage(), "해당 사용자는 탈퇴한 사용자입니다.")) { + return ErrorStatus.USER_DEACTIVATED; + } else if (failed instanceof InternalAuthenticationServiceException) { + return ErrorStatus.MEMBER_NOT_FOUND; + } else if (Objects.equals(failed.getMessage(), "자격 증명에 실패하였습니다.")) { + return ErrorStatus.PASSWORD_INVALID; + } else { + return ErrorStatus._UNAUTHORIZED; + } } } diff --git a/src/main/java/com/gamegoo/security/SecurityUtil.java b/src/main/java/com/gamegoo/security/SecurityUtil.java index 4c97e35c..8fbd8bb0 100644 --- a/src/main/java/com/gamegoo/security/SecurityUtil.java +++ b/src/main/java/com/gamegoo/security/SecurityUtil.java @@ -7,7 +7,7 @@ public class SecurityUtil { public static Long getCurrentUserId() { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - if (authentication != null && authentication.getPrincipal() instanceof CustomMemberDetails memberDetails) { + if (authentication != null && authentication.getPrincipal() instanceof CustomUserDetails memberDetails) { return memberDetails.getId(); } diff --git a/src/main/java/com/gamegoo/service/member/CustomMemberDetailService.java b/src/main/java/com/gamegoo/service/member/CustomMemberDetailService.java deleted file mode 100644 index 96db5aed..00000000 --- a/src/main/java/com/gamegoo/service/member/CustomMemberDetailService.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.gamegoo.service.member; - -import com.gamegoo.apiPayload.code.status.ErrorStatus; -import com.gamegoo.apiPayload.exception.handler.MemberNotFoundExceptionHandler; -import com.gamegoo.apiPayload.exception.handler.UserDeactivatedExceptionHandler; -import com.gamegoo.domain.Member; -import com.gamegoo.repository.member.MemberRepository; -import com.gamegoo.security.CustomMemberDetails; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.stereotype.Service; - -import java.util.Optional; - -// 로그인 DB 로직 -@Service -public class CustomMemberDetailService implements UserDetailsService { - private final MemberRepository memberRepository; - - public CustomMemberDetailService(MemberRepository memberRepository) { - - this.memberRepository = memberRepository; - } - - @Override - public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { - - // DB에서 조회 - Optional member = memberRepository.findByEmail(email); - Member memberData; - - if (member.isPresent()) { - memberData = member.get(); - - if (memberData.getBlind()) { - throw new UserDeactivatedExceptionHandler(ErrorStatus.USER_DEACTIVATED); - } - } else { - throw new MemberNotFoundExceptionHandler(ErrorStatus.MEMBER_NOT_FOUND); - - } - - - // memberDetails에 담아서 return하면 AuthenticationManager가 검증함 - return new CustomMemberDetails(memberData); - } -} diff --git a/src/main/java/com/gamegoo/service/member/DeleteService.java b/src/main/java/com/gamegoo/service/member/DeleteService.java index 04e576f5..7fd3d0cc 100644 --- a/src/main/java/com/gamegoo/service/member/DeleteService.java +++ b/src/main/java/com/gamegoo/service/member/DeleteService.java @@ -1,7 +1,7 @@ package com.gamegoo.service.member; import com.gamegoo.apiPayload.code.status.ErrorStatus; -import com.gamegoo.apiPayload.exception.handler.UserDeactivatedExceptionHandler; +import com.gamegoo.apiPayload.exception.handler.MemberHandler; import com.gamegoo.domain.Member; import com.gamegoo.repository.member.MemberRepository; import org.springframework.beans.factory.annotation.Autowired; @@ -26,7 +26,7 @@ public void deleteMember(Long userId) { member.setBlind(true); memberRepository.save(member); } else { - throw new UserDeactivatedExceptionHandler(ErrorStatus.MEMBER_NOT_FOUND); + throw new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND); } } diff --git a/src/main/java/com/gamegoo/service/member/JoinService.java b/src/main/java/com/gamegoo/service/member/JoinService.java index 36bb3052..f09127f0 100644 --- a/src/main/java/com/gamegoo/service/member/JoinService.java +++ b/src/main/java/com/gamegoo/service/member/JoinService.java @@ -27,7 +27,6 @@ public void JoinMember(JoinDTO joinDTO) { // DTO로부터 데이터 받기 String email = joinDTO.getEmail(); String password = joinDTO.getPassword(); - // 중복 확인은 이메일 인증 코드 발급 API에서 진행 (로직이 이메일 인증 API -> 회원가입 API) // DB에 넣을 정보 설정 diff --git a/src/main/java/com/gamegoo/service/member/PasswordService.java b/src/main/java/com/gamegoo/service/member/PasswordService.java index aaacf513..05b7722f 100644 --- a/src/main/java/com/gamegoo/service/member/PasswordService.java +++ b/src/main/java/com/gamegoo/service/member/PasswordService.java @@ -1,7 +1,7 @@ package com.gamegoo.service.member; import com.gamegoo.apiPayload.code.status.ErrorStatus; -import com.gamegoo.apiPayload.exception.handler.UserDeactivatedExceptionHandler; +import com.gamegoo.apiPayload.exception.handler.MemberHandler; import com.gamegoo.domain.Member; import com.gamegoo.repository.member.MemberRepository; import org.springframework.beans.factory.annotation.Autowired; @@ -35,7 +35,7 @@ public void updatePassword(Long userId, String newPassword) { member.setPassword(bCryptPasswordEncoder.encode(newPassword)); memberRepository.save(member); } else { - throw new UserDeactivatedExceptionHandler(ErrorStatus.MEMBER_NOT_FOUND); + throw new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND); } } } From 9487cb7440f5c6728d8be01770aa5aa347924222 Mon Sep 17 00:00:00 2001 From: Rimi Date: Fri, 28 Jun 2024 09:50:52 +0900 Subject: [PATCH 03/11] =?UTF-8?q?:bug:=20[fix]=20jwt=20token=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=EC=B2=98=EB=A6=AC=20=EC=88=98=EC=A0=95,=20JWTExceptio?= =?UTF-8?q?nHandlerFilter=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../handler/JWTExceptionHandlerFilter.java | 41 +++++++++++++++++++ .../com/gamegoo/config/SecurityConfig.java | 3 +- .../controller/member/PasswordController.java | 1 + src/main/java/com/gamegoo/jwt/JWTFilter.java | 20 ++++----- .../com/gamegoo/security/LoginFilter.java | 9 ++-- 5 files changed, 57 insertions(+), 17 deletions(-) create mode 100644 src/main/java/com/gamegoo/apiPayload/exception/handler/JWTExceptionHandlerFilter.java diff --git a/src/main/java/com/gamegoo/apiPayload/exception/handler/JWTExceptionHandlerFilter.java b/src/main/java/com/gamegoo/apiPayload/exception/handler/JWTExceptionHandlerFilter.java new file mode 100644 index 00000000..654b896d --- /dev/null +++ b/src/main/java/com/gamegoo/apiPayload/exception/handler/JWTExceptionHandlerFilter.java @@ -0,0 +1,41 @@ +package com.gamegoo.apiPayload.exception.handler; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.gamegoo.apiPayload.ApiResponse; +import com.gamegoo.apiPayload.code.status.ErrorStatus; +import io.jsonwebtoken.JwtException; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Objects; + +public class JWTExceptionHandlerFilter extends OncePerRequestFilter { + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + try { + filterChain.doFilter(request, response); + } catch (JwtException e) { + if (Objects.equals(e.getMessage(), "Token expired")) { + setErrorResponse(response, ErrorStatus.TOKEN_EXPIRED); + } else if (Objects.equals(e.getMessage(), "Invalid token")) { + setErrorResponse(response, ErrorStatus.INVALID_TOKEN); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private void setErrorResponse(HttpServletResponse response, ErrorStatus errorStatus) throws IOException { + // 에러 응답 생성하기 + ApiResponse apiResponse = ApiResponse.onFailure(errorStatus.getCode(), errorStatus.getMessage(), null); + response.setStatus(errorStatus.getHttpStatus().value()); + response.setContentType("application/json"); + response.setCharacterEncoding("UTF-8"); + new ObjectMapper().writeValue(response.getWriter(), apiResponse); + } +} + diff --git a/src/main/java/com/gamegoo/config/SecurityConfig.java b/src/main/java/com/gamegoo/config/SecurityConfig.java index 051125f5..a505d6be 100644 --- a/src/main/java/com/gamegoo/config/SecurityConfig.java +++ b/src/main/java/com/gamegoo/config/SecurityConfig.java @@ -1,5 +1,6 @@ package com.gamegoo.config; +import com.gamegoo.apiPayload.exception.handler.JWTExceptionHandlerFilter; import com.gamegoo.jwt.JWTFilter; import com.gamegoo.jwt.JWTUtil; import com.gamegoo.security.CustomUserDetailService; @@ -59,7 +60,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .authorizeHttpRequests((auth) -> auth .antMatchers("/api/member/join", "/api/member/login", "/api/member/email").permitAll() .anyRequest().authenticated()) - + .addFilterBefore(new JWTExceptionHandlerFilter(), UsernamePasswordAuthenticationFilter.class) .addFilterAt(new LoginFilter(authenticationManager(authenticationConfiguration), jwtUtil), UsernamePasswordAuthenticationFilter.class) .addFilterBefore(jwtFilter(), LoginFilter.class) .sessionManagement((session) -> session diff --git a/src/main/java/com/gamegoo/controller/member/PasswordController.java b/src/main/java/com/gamegoo/controller/member/PasswordController.java index 10b5b138..d3181c25 100644 --- a/src/main/java/com/gamegoo/controller/member/PasswordController.java +++ b/src/main/java/com/gamegoo/controller/member/PasswordController.java @@ -23,6 +23,7 @@ public class PasswordController { @Operation(summary = "비밀번호 확인 API 입니다.", description = "API for checking password") public ApiResponse checkPassword(@RequestBody PasswordDTO passwordDTO) { Long currentUserId = SecurityUtil.getCurrentUserId(); //헤더에 있는 jwt 토큰에서 id를 가져오는 코드 + boolean isPasswordValid = passwordService.checkPasswordById(currentUserId, passwordDTO.getPassword()); //request body에 있는 password와 currentUserId를 전달 if (isPasswordValid) { diff --git a/src/main/java/com/gamegoo/jwt/JWTFilter.java b/src/main/java/com/gamegoo/jwt/JWTFilter.java index b87b4ae8..bc51dbf0 100644 --- a/src/main/java/com/gamegoo/jwt/JWTFilter.java +++ b/src/main/java/com/gamegoo/jwt/JWTFilter.java @@ -4,6 +4,8 @@ import com.gamegoo.apiPayload.exception.handler.MemberHandler; import com.gamegoo.security.CustomUserDetailService; import com.gamegoo.security.CustomUserDetails; +import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.JwtException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; @@ -33,7 +35,7 @@ public JWTFilter(JWTUtil jwtUtil, List excludedPaths, CustomUserDetailSe } @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException, JwtException { String requestURI = request.getRequestURI(); // JWT Filter를 사용하지 않는 Path는 제외 @@ -55,16 +57,10 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse // Bearer 부분 제거 후 순수 토큰만 획득 String token = authorization.split(" ")[1]; - try { - // 토큰 소멸 시간 검증 - if (jwtUtil.isExpired(token)) { - throw new MemberHandler(ErrorStatus.TOKEN_EXPIRED); - } - // jwt 토큰에서 id 획득 Long id = jwtUtil.getId(token); - + System.out.println(id); // UserDetails에 회원 정보 객체 담기 CustomUserDetails customUserDetails = (CustomUserDetails) customUserDetailService.loadUserById(id); @@ -76,10 +72,12 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse SecurityContextHolder.getContext().setAuthentication(authToken); filterChain.doFilter(request, response); - - } catch (Exception e) { - throw new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND); + } catch (ExpiredJwtException e) { + throw new JwtException("Token expired"); + } catch (JwtException e) { + throw new JwtException("Invalid token"); } + } } diff --git a/src/main/java/com/gamegoo/security/LoginFilter.java b/src/main/java/com/gamegoo/security/LoginFilter.java index f2733861..bfbd7bc4 100644 --- a/src/main/java/com/gamegoo/security/LoginFilter.java +++ b/src/main/java/com/gamegoo/security/LoginFilter.java @@ -55,14 +55,11 @@ protected void successfulAuthentication(HttpServletRequest request, HttpServletR Long id = customUserDetails.getId(); // jwt 토큰 생성 (만료시간 10시간) - String token = jwtUtil.createJwt(id, 60 * 60 * 10000L); + String token = jwtUtil.createJwt(id, 60 * 60 * 100000L); // 헤더에 추가 response.addHeader("Authorization", "Bearer " + token); - // 바디에 추가 - - // 성공 응답 생성 ApiResponse apiResponse = ApiResponse.onSuccess(token); @@ -74,9 +71,11 @@ protected void successfulAuthentication(HttpServletRequest request, HttpServletR // 로그인 실패시 실행하는 메소드 @Override protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException { + // 어떤 에러인지 확인 ErrorStatus errorStatus = getErrorStatus(failed); - ApiResponse apiResponse = ApiResponse.onFailure(errorStatus.getCode(), errorStatus.getMessage(), null); + // 에러 응답 생성하기 + ApiResponse apiResponse = ApiResponse.onFailure(errorStatus.getCode(), errorStatus.getMessage(), null); response.setStatus(errorStatus.getHttpStatus().value()); apiResponse(response, apiResponse); } From 41f7ba578871ca11dd1fb3332a99e49ad1f16c10 Mon Sep 17 00:00:00 2001 From: Rimi Date: Fri, 28 Jun 2024 15:59:52 +0900 Subject: [PATCH 04/11] =?UTF-8?q?:sparkles:=20[feat]=20jwt=20refresh=20tok?= =?UTF-8?q?en=EC=9A=A9=20DB=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/gamegoo/domain/Member.java | 3 ++ .../gamegoo/security/RefreshTokenService.java | 30 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 src/main/java/com/gamegoo/security/RefreshTokenService.java diff --git a/src/main/java/com/gamegoo/domain/Member.java b/src/main/java/com/gamegoo/domain/Member.java index af5d8e2c..e17a2cfa 100644 --- a/src/main/java/com/gamegoo/domain/Member.java +++ b/src/main/java/com/gamegoo/domain/Member.java @@ -61,6 +61,9 @@ public class Member extends BaseDateTimeEntity { @Column(name = "sub_position") private int subPosition; + @Column(name = "refresh_token") + private String refreshToken; + @OneToMany(mappedBy = "member", cascade = CascadeType.ALL) private List boardList = new ArrayList<>(); diff --git a/src/main/java/com/gamegoo/security/RefreshTokenService.java b/src/main/java/com/gamegoo/security/RefreshTokenService.java new file mode 100644 index 00000000..012d8420 --- /dev/null +++ b/src/main/java/com/gamegoo/security/RefreshTokenService.java @@ -0,0 +1,30 @@ +package com.gamegoo.security; + +import com.gamegoo.domain.Member; +import com.gamegoo.jwt.JWTUtil; +import com.gamegoo.repository.member.MemberRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class RefreshTokenService { + + @Autowired + private MemberRepository memberRepository; + + @Autowired + private JWTUtil jwtUtil; + + public void saveRefreshToken(Long id, String refresh_token) { + Member member = memberRepository.findById(id) + .orElseThrow(); + member.setRefreshToken(refresh_token); + memberRepository.save(member); + + } + + public boolean isRefreshTokenExpired(String refreshToken) { + return jwtUtil.isExpired(refreshToken); + } + +} From 98197b17bf74bec2d696904fc0eb5ef4a5766341 Mon Sep 17 00:00:00 2001 From: Rimi Date: Sat, 29 Jun 2024 15:58:48 +0900 Subject: [PATCH 05/11] =?UTF-8?q?:recycle:=20[Refactor]=20=EC=BB=A8?= =?UTF-8?q?=ED=8A=B8=EB=A1=A4=EB=9F=AC,=20=EC=84=9C=EB=B9=84=EC=8A=A4,=20?= =?UTF-8?q?=EC=8B=9C=ED=81=90=EB=A6=AC=ED=8B=B0=20=ED=8F=B4=EB=8D=94,=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 2 +- .../com/gamegoo/config/SecurityConfig.java | 15 ++- ...ailController.java => AuthController.java} | 19 +++- .../controller/member/DeleteController.java | 36 -------- .../controller/member/JoinController.java | 30 ------ .../member/MemberGameStyleController.java | 29 ------ .../controller/member/PasswordController.java | 2 +- .../controller/member/PositionController.java | 31 ------- .../controller/member/ProfileController.java | 61 ++++++++++++ .../member/ProfileImageController.java | 31 ------- .../gamegoo/{jwt => filter}/JWTFilter.java | 5 +- .../{security => filter}/LoginFilter.java | 5 +- .../gamegoo/scripts/GameStyleInitializer.java | 8 +- .../gamegoo/security/CustomUserDetails.java | 7 +- .../{EmailService.java => AuthService.java} | 36 ++++++-- .../member}/CustomUserDetailService.java | 17 ++-- .../gamegoo/service/member/DeleteService.java | 33 ------- .../gamegoo/service/member/JoinService.java | 44 --------- .../service/member/PasswordService.java | 9 +- .../service/member/PositionService.java | 58 ------------ .../service/member/ProfileImageService.java | 56 ----------- ...eStyleService.java => ProfileService.java} | 92 ++++++++++++++++--- .../member}/RefreshTokenService.java | 10 +- .../{security => util}/CodeGeneratorUtil.java | 2 +- .../com/gamegoo/{jwt => util}/JWTUtil.java | 2 +- .../{security => util}/SecurityUtil.java | 3 +- 26 files changed, 217 insertions(+), 426 deletions(-) rename src/main/java/com/gamegoo/controller/member/{EmailController.java => AuthController.java} (61%) delete mode 100644 src/main/java/com/gamegoo/controller/member/DeleteController.java delete mode 100644 src/main/java/com/gamegoo/controller/member/JoinController.java delete mode 100644 src/main/java/com/gamegoo/controller/member/MemberGameStyleController.java delete mode 100644 src/main/java/com/gamegoo/controller/member/PositionController.java create mode 100644 src/main/java/com/gamegoo/controller/member/ProfileController.java delete mode 100644 src/main/java/com/gamegoo/controller/member/ProfileImageController.java rename src/main/java/com/gamegoo/{jwt => filter}/JWTFilter.java (96%) rename src/main/java/com/gamegoo/{security => filter}/LoginFilter.java (97%) rename src/main/java/com/gamegoo/service/member/{EmailService.java => AuthService.java} (71%) rename src/main/java/com/gamegoo/{security => service/member}/CustomUserDetailService.java (73%) delete mode 100644 src/main/java/com/gamegoo/service/member/DeleteService.java delete mode 100644 src/main/java/com/gamegoo/service/member/JoinService.java delete mode 100644 src/main/java/com/gamegoo/service/member/PositionService.java delete mode 100644 src/main/java/com/gamegoo/service/member/ProfileImageService.java rename src/main/java/com/gamegoo/service/member/{MemberGameStyleService.java => ProfileService.java} (54%) rename src/main/java/com/gamegoo/{security => service/member}/RefreshTokenService.java (80%) rename src/main/java/com/gamegoo/{security => util}/CodeGeneratorUtil.java (95%) rename src/main/java/com/gamegoo/{jwt => util}/JWTUtil.java (97%) rename src/main/java/com/gamegoo/{security => util}/SecurityUtil.java (88%) diff --git a/Dockerfile b/Dockerfile index 1bd246b7..58b52f81 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,4 +4,4 @@ ARG JAR_FILE=/build/libs/gamegoo-0.0.1-SNAPSHOT.jar COPY ${JAR_FILE} /gamegoo.jar -ENTRYPOINT ["java","-jar","-Dspring.profiles.active=prod", "/gamegoo.jar"] \ No newline at end of file +ENTRYPOINT ["java","-jar","-Dspring.profiles.active=prod", "/gamegoo.jar"] diff --git a/src/main/java/com/gamegoo/config/SecurityConfig.java b/src/main/java/com/gamegoo/config/SecurityConfig.java index a505d6be..9c99f33e 100644 --- a/src/main/java/com/gamegoo/config/SecurityConfig.java +++ b/src/main/java/com/gamegoo/config/SecurityConfig.java @@ -1,10 +1,11 @@ package com.gamegoo.config; import com.gamegoo.apiPayload.exception.handler.JWTExceptionHandlerFilter; -import com.gamegoo.jwt.JWTFilter; -import com.gamegoo.jwt.JWTUtil; -import com.gamegoo.security.CustomUserDetailService; -import com.gamegoo.security.LoginFilter; +import com.gamegoo.filter.JWTFilter; +import com.gamegoo.filter.LoginFilter; +import com.gamegoo.service.member.CustomUserDetailService; +import com.gamegoo.util.JWTUtil; +import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; @@ -22,16 +23,12 @@ @Configuration @EnableWebSecurity +@RequiredArgsConstructor public class SecurityConfig { private final AuthenticationConfiguration authenticationConfiguration; private final JWTUtil jwtUtil; private final CustomUserDetailService customUserDetailService; - public SecurityConfig(AuthenticationConfiguration authenticationConfiguration, JWTUtil jwtUtil, CustomUserDetailService customUserDetailService) { - this.authenticationConfiguration = authenticationConfiguration; - this.jwtUtil = jwtUtil; - this.customUserDetailService = customUserDetailService; - } @Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception { diff --git a/src/main/java/com/gamegoo/controller/member/EmailController.java b/src/main/java/com/gamegoo/controller/member/AuthController.java similarity index 61% rename from src/main/java/com/gamegoo/controller/member/EmailController.java rename to src/main/java/com/gamegoo/controller/member/AuthController.java index e805e73c..dc5f1a40 100644 --- a/src/main/java/com/gamegoo/controller/member/EmailController.java +++ b/src/main/java/com/gamegoo/controller/member/AuthController.java @@ -2,7 +2,8 @@ import com.gamegoo.apiPayload.ApiResponse; import com.gamegoo.dto.member.EmailDTO; -import com.gamegoo.service.member.EmailService; +import com.gamegoo.dto.member.JoinDTO; +import com.gamegoo.service.member.AuthService; import io.swagger.v3.oas.annotations.Operation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -17,15 +18,23 @@ @RequiredArgsConstructor @RequestMapping("/api/member") @Slf4j -public class EmailController { - private final EmailService emailService; +public class AuthController { + private final AuthService authService; + + @PostMapping("/join") + @Operation(summary = "회원가입 API 입니다.", description = "API for join") + public ApiResponse joinMember(@RequestBody JoinDTO joinDTO) { + System.out.println(joinDTO.getPassword()); + System.out.println(joinDTO.getEmail()); + authService.JoinMember(joinDTO); + return ApiResponse.onSuccess(null); + } @PostMapping("/email") @Operation(summary = "이메일 인증코드 전송 API 입니다.", description = "API for email verification") public ApiResponse verifyEmail(@RequestBody EmailDTO emailDTO) throws IOException { String emailAddress = emailDTO.getEmail_address(); - String code = emailService.verifyEmail(emailAddress); + String code = authService.verifyEmail(emailAddress); return ApiResponse.onSuccess(code); } - } diff --git a/src/main/java/com/gamegoo/controller/member/DeleteController.java b/src/main/java/com/gamegoo/controller/member/DeleteController.java deleted file mode 100644 index 954bc3a6..00000000 --- a/src/main/java/com/gamegoo/controller/member/DeleteController.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.gamegoo.controller.member; - -import com.gamegoo.apiPayload.ApiResponse; -import com.gamegoo.apiPayload.code.status.ErrorStatus; -import com.gamegoo.apiPayload.exception.handler.MemberHandler; -import com.gamegoo.security.SecurityUtil; -import com.gamegoo.service.member.DeleteService; -import io.swagger.v3.oas.annotations.Operation; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequiredArgsConstructor -@RequestMapping("/api/member") -@Slf4j -public class DeleteController { - - private final DeleteService deleteService; - - @DeleteMapping("") - @Operation(summary = "회원 탈퇴 API 입니다.", description = "API for Member") - public ApiResponse blindMember() { - Long userId = SecurityUtil.getCurrentUserId(); //헤더에 있는 jwt 토큰에서 id를 가져오는 코드 - try { - deleteService.deleteMember(userId); - return ApiResponse.onSuccess(null); - } catch (Exception e) { - throw new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND); - } - } - - -} diff --git a/src/main/java/com/gamegoo/controller/member/JoinController.java b/src/main/java/com/gamegoo/controller/member/JoinController.java deleted file mode 100644 index 6490f375..00000000 --- a/src/main/java/com/gamegoo/controller/member/JoinController.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.gamegoo.controller.member; - -import com.gamegoo.apiPayload.ApiResponse; -import com.gamegoo.dto.member.JoinDTO; -import com.gamegoo.service.member.JoinService; -import io.swagger.v3.oas.annotations.Operation; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequiredArgsConstructor -@RequestMapping("/api/member") -@Slf4j -public class JoinController { - private final JoinService joinService; - - @PostMapping("/join") - @Operation(summary = "회원가입 API 입니다.", description = "API for join") - public ApiResponse joinMember(@RequestBody JoinDTO joinDTO) { - System.out.println(joinDTO.getPassword()); - System.out.println(joinDTO.getEmail()); - joinService.JoinMember(joinDTO); - return ApiResponse.onSuccess(null); - } - -} diff --git a/src/main/java/com/gamegoo/controller/member/MemberGameStyleController.java b/src/main/java/com/gamegoo/controller/member/MemberGameStyleController.java deleted file mode 100644 index 461636fa..00000000 --- a/src/main/java/com/gamegoo/controller/member/MemberGameStyleController.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.gamegoo.controller.member; - -import com.gamegoo.apiPayload.ApiResponse; -import com.gamegoo.dto.member.GameStyleDTO; -import com.gamegoo.service.member.MemberGameStyleService; -import io.swagger.v3.oas.annotations.Operation; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import java.io.IOException; - -@RestController -@RequiredArgsConstructor -@RequestMapping("/api/member") -@Slf4j -public class MemberGameStyleController { - private final MemberGameStyleService memberGameStyleService; - - @PutMapping("/gamestyle") - @Operation(summary = "gamestyle 추가 및 수정 API 입니다.", description = "API for Gamestyle addition and modification ") - public ApiResponse addGameStyle(@RequestBody GameStyleDTO gameStyleDTO) throws IOException { - memberGameStyleService.addMemberGameStyles(gameStyleDTO.getGamestyle()); - return ApiResponse.onSuccess(null); - } -} diff --git a/src/main/java/com/gamegoo/controller/member/PasswordController.java b/src/main/java/com/gamegoo/controller/member/PasswordController.java index d3181c25..2bd4ede7 100644 --- a/src/main/java/com/gamegoo/controller/member/PasswordController.java +++ b/src/main/java/com/gamegoo/controller/member/PasswordController.java @@ -2,8 +2,8 @@ import com.gamegoo.apiPayload.ApiResponse; import com.gamegoo.dto.member.PasswordDTO; -import com.gamegoo.security.SecurityUtil; import com.gamegoo.service.member.PasswordService; +import com.gamegoo.util.SecurityUtil; import io.swagger.v3.oas.annotations.Operation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; diff --git a/src/main/java/com/gamegoo/controller/member/PositionController.java b/src/main/java/com/gamegoo/controller/member/PositionController.java deleted file mode 100644 index 711972ff..00000000 --- a/src/main/java/com/gamegoo/controller/member/PositionController.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.gamegoo.controller.member; - -import com.gamegoo.apiPayload.ApiResponse; -import com.gamegoo.dto.member.PositionDTO; -import com.gamegoo.service.member.PositionService; -import io.swagger.v3.oas.annotations.Operation; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import java.io.IOException; - -@RestController -@RequiredArgsConstructor -@RequestMapping("/api/member") -@Slf4j -public class PositionController { - private final PositionService positionService; - - @PutMapping("/position") - @Operation(summary = "주/부 포지션 수정 API 입니다.", description = "API for Main/Sub Position Modification") - public ApiResponse modifyPosition(@RequestBody PositionDTO positionDTO) throws IOException { - int mainP = positionDTO.getMainP(); - int subP = positionDTO.getSubP(); - positionService.modifyPosition(mainP, subP); - return ApiResponse.onSuccess(null); - } -} diff --git a/src/main/java/com/gamegoo/controller/member/ProfileController.java b/src/main/java/com/gamegoo/controller/member/ProfileController.java new file mode 100644 index 00000000..995e48ef --- /dev/null +++ b/src/main/java/com/gamegoo/controller/member/ProfileController.java @@ -0,0 +1,61 @@ +package com.gamegoo.controller.member; + +import com.gamegoo.apiPayload.ApiResponse; +import com.gamegoo.apiPayload.code.status.ErrorStatus; +import com.gamegoo.apiPayload.exception.handler.MemberHandler; +import com.gamegoo.dto.member.GameStyleDTO; +import com.gamegoo.dto.member.PositionDTO; +import com.gamegoo.dto.member.ProfileImageDTO; +import com.gamegoo.service.member.ProfileService; +import com.gamegoo.util.SecurityUtil; +import io.swagger.v3.oas.annotations.Operation; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/member") +@Slf4j +public class ProfileController { + private final ProfileService profileService; + + @PutMapping("/gamestyle") + @Operation(summary = "gamestyle 추가 및 수정 API 입니다.", description = "API for Gamestyle addition and modification ") + public ApiResponse addGameStyle(@RequestBody GameStyleDTO gameStyleDTO) throws IOException { + profileService.addMemberGameStyles(gameStyleDTO.getGamestyle()); + return ApiResponse.onSuccess(null); + } + + @PutMapping("/position") + @Operation(summary = "주/부 포지션 수정 API 입니다.", description = "API for Main/Sub Position Modification") + public ApiResponse modifyPosition(@RequestBody PositionDTO positionDTO) throws IOException { + int mainP = positionDTO.getMainP(); + int subP = positionDTO.getSubP(); + profileService.modifyPosition(mainP, subP); + return ApiResponse.onSuccess(null); + } + + @PutMapping("/profile_image") + @Operation(summary = "프로필 이미지 수정 API 입니다.", description = "API for Profile Image Modification") + public ApiResponse modifyPosition(@RequestBody ProfileImageDTO profileImageDTO) throws IOException { + String profileImage = profileImageDTO.getProfile_image(); + profileService.modifyProfileImage(profileImage); + return ApiResponse.onSuccess(null); + } + + @DeleteMapping("") + @Operation(summary = "회원 탈퇴 API 입니다.", description = "API for Member") + public ApiResponse blindMember() { + Long userId = SecurityUtil.getCurrentUserId(); //헤더에 있는 jwt 토큰에서 id를 가져오는 코드 + try { + profileService.deleteMember(userId); + return ApiResponse.onSuccess(null); + } catch (Exception e) { + throw new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND); + } + } + +} diff --git a/src/main/java/com/gamegoo/controller/member/ProfileImageController.java b/src/main/java/com/gamegoo/controller/member/ProfileImageController.java deleted file mode 100644 index 515637e9..00000000 --- a/src/main/java/com/gamegoo/controller/member/ProfileImageController.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.gamegoo.controller.member; - -import com.gamegoo.apiPayload.ApiResponse; -import com.gamegoo.dto.member.ProfileImageDTO; -import com.gamegoo.service.member.ProfileImageService; -import io.swagger.v3.oas.annotations.Operation; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import java.io.IOException; - -@RestController -@RequiredArgsConstructor -@RequestMapping("/api/member") -@Slf4j -public class ProfileImageController { - private final ProfileImageService profileImageService; - - @PutMapping("/profile_image") - @Operation(summary = "프로필 이미지 수정 API 입니다.", description = "API for Profile Image Modification") - public ApiResponse modifyPosition(@RequestBody ProfileImageDTO profileImageDTO) throws IOException { - String profileImage = profileImageDTO.getProfile_image(); - profileImageService.modifyPosition(profileImage); - return ApiResponse.onSuccess(null); - } - -} diff --git a/src/main/java/com/gamegoo/jwt/JWTFilter.java b/src/main/java/com/gamegoo/filter/JWTFilter.java similarity index 96% rename from src/main/java/com/gamegoo/jwt/JWTFilter.java rename to src/main/java/com/gamegoo/filter/JWTFilter.java index bc51dbf0..425962d9 100644 --- a/src/main/java/com/gamegoo/jwt/JWTFilter.java +++ b/src/main/java/com/gamegoo/filter/JWTFilter.java @@ -1,9 +1,10 @@ -package com.gamegoo.jwt; +package com.gamegoo.filter; import com.gamegoo.apiPayload.code.status.ErrorStatus; import com.gamegoo.apiPayload.exception.handler.MemberHandler; -import com.gamegoo.security.CustomUserDetailService; import com.gamegoo.security.CustomUserDetails; +import com.gamegoo.service.member.CustomUserDetailService; +import com.gamegoo.util.JWTUtil; import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.JwtException; import org.springframework.beans.factory.annotation.Autowired; diff --git a/src/main/java/com/gamegoo/security/LoginFilter.java b/src/main/java/com/gamegoo/filter/LoginFilter.java similarity index 97% rename from src/main/java/com/gamegoo/security/LoginFilter.java rename to src/main/java/com/gamegoo/filter/LoginFilter.java index bfbd7bc4..bbbe7cdb 100644 --- a/src/main/java/com/gamegoo/security/LoginFilter.java +++ b/src/main/java/com/gamegoo/filter/LoginFilter.java @@ -1,9 +1,10 @@ -package com.gamegoo.security; +package com.gamegoo.filter; import com.fasterxml.jackson.databind.ObjectMapper; import com.gamegoo.apiPayload.ApiResponse; import com.gamegoo.apiPayload.code.status.ErrorStatus; -import com.gamegoo.jwt.JWTUtil; +import com.gamegoo.security.CustomUserDetails; +import com.gamegoo.util.JWTUtil; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.InternalAuthenticationServiceException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; diff --git a/src/main/java/com/gamegoo/scripts/GameStyleInitializer.java b/src/main/java/com/gamegoo/scripts/GameStyleInitializer.java index 58a1b8bc..1564e082 100644 --- a/src/main/java/com/gamegoo/scripts/GameStyleInitializer.java +++ b/src/main/java/com/gamegoo/scripts/GameStyleInitializer.java @@ -2,21 +2,17 @@ import com.gamegoo.domain.gamestyle.GameStyle; import com.gamegoo.repository.member.GameStyleRepository; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.RequiredArgsConstructor; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; @Component +@RequiredArgsConstructor public class GameStyleInitializer implements ApplicationListener { private final GameStyleRepository gameStyleRepository; - @Autowired - public GameStyleInitializer(GameStyleRepository gameStyleRepository) { - this.gameStyleRepository = gameStyleRepository; - } - @Override public void onApplicationEvent(ApplicationReadyEvent event) { if (isCreateMode(event)) { diff --git a/src/main/java/com/gamegoo/security/CustomUserDetails.java b/src/main/java/com/gamegoo/security/CustomUserDetails.java index 0cd51d21..abcc5f0f 100644 --- a/src/main/java/com/gamegoo/security/CustomUserDetails.java +++ b/src/main/java/com/gamegoo/security/CustomUserDetails.java @@ -1,6 +1,7 @@ package com.gamegoo.security; import com.gamegoo.domain.Member; +import lombok.RequiredArgsConstructor; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; @@ -8,14 +9,10 @@ import java.util.Collection; // UserDetails 오버라이딩해서 Spring Security의 Login Filter에 사용하는 클래스 +@RequiredArgsConstructor public class CustomUserDetails implements UserDetails { private final Member member; - public CustomUserDetails(Member member) { - - this.member = member; - } - @Override public Collection getAuthorities() { diff --git a/src/main/java/com/gamegoo/service/member/EmailService.java b/src/main/java/com/gamegoo/service/member/AuthService.java similarity index 71% rename from src/main/java/com/gamegoo/service/member/EmailService.java rename to src/main/java/com/gamegoo/service/member/AuthService.java index ca7b019e..b63aad16 100644 --- a/src/main/java/com/gamegoo/service/member/EmailService.java +++ b/src/main/java/com/gamegoo/service/member/AuthService.java @@ -4,11 +4,14 @@ import com.gamegoo.apiPayload.ApiResponse; import com.gamegoo.apiPayload.code.status.ErrorStatus; import com.gamegoo.domain.Member; +import com.gamegoo.domain.enums.LoginType; +import com.gamegoo.dto.member.JoinDTO; import com.gamegoo.repository.member.MemberRepository; -import com.gamegoo.security.CodeGeneratorUtil; -import org.springframework.beans.factory.annotation.Autowired; +import com.gamegoo.util.CodeGeneratorUtil; +import lombok.RequiredArgsConstructor; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; import javax.mail.MessagingException; @@ -18,16 +21,32 @@ import java.util.Optional; @Service -public class EmailService { +@RequiredArgsConstructor +public class AuthService { private final MemberRepository memberRepository; + private final BCryptPasswordEncoder bCryptPasswordEncoder; private final JavaMailSender javaMailSender; private final HttpServletResponse response; - @Autowired - public EmailService(MemberRepository memberRepository, JavaMailSender javaMailSender, HttpServletResponse response) { - this.memberRepository = memberRepository; - this.javaMailSender = javaMailSender; - this.response = response; + // 회원가입 로직 + public void JoinMember(JoinDTO joinDTO) { + + // DTO로부터 데이터 받기 + String email = joinDTO.getEmail(); + String password = joinDTO.getPassword(); + // 중복 확인은 이메일 인증 코드 발급 API에서 진행 (로직이 이메일 인증 API -> 회원가입 API) + + // DB에 넣을 정보 설정 + Member member = Member.builder() + .email(email) + .password(bCryptPasswordEncoder.encode(password)) + .loginType(LoginType.GENERAL) + .profileImage("default") + .blind(false) + .build(); + + // DB에 저장 + memberRepository.save(member); } //이메일 인증 및 전송 @@ -73,4 +92,5 @@ private String getCertificationMessage(String certificationNumber) { return certificationMessage; } + } diff --git a/src/main/java/com/gamegoo/security/CustomUserDetailService.java b/src/main/java/com/gamegoo/service/member/CustomUserDetailService.java similarity index 73% rename from src/main/java/com/gamegoo/security/CustomUserDetailService.java rename to src/main/java/com/gamegoo/service/member/CustomUserDetailService.java index 9da10c0c..c4f4e40e 100644 --- a/src/main/java/com/gamegoo/security/CustomUserDetailService.java +++ b/src/main/java/com/gamegoo/service/member/CustomUserDetailService.java @@ -1,10 +1,11 @@ -package com.gamegoo.security; +package com.gamegoo.service.member; -import com.gamegoo.apiPayload.code.status.ErrorStatus; import com.gamegoo.apiPayload.exception.CustomUserException; -import com.gamegoo.apiPayload.exception.handler.MemberHandler; import com.gamegoo.domain.Member; import com.gamegoo.repository.member.MemberRepository; +import com.gamegoo.security.CustomUserDetails; +import io.jsonwebtoken.JwtException; +import lombok.RequiredArgsConstructor; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; @@ -12,14 +13,10 @@ // 로그인 DB 로직 @Service +@RequiredArgsConstructor public class CustomUserDetailService implements UserDetailsService { private final MemberRepository memberRepository; - public CustomUserDetailService(MemberRepository memberRepository) { - - this.memberRepository = memberRepository; - } - @Override public UserDetails loadUserByUsername(String email) { return memberRepository.findByEmail(email) @@ -29,13 +26,13 @@ public UserDetails loadUserByUsername(String email) { } return new CustomUserDetails(member); }) - .orElseThrow(() -> new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND)); + .orElseThrow(() -> new JwtException("해당 사용자를 찾을 수 없습니다.")); } public UserDetails loadUserById(Long id) throws UsernameNotFoundException { Member member = memberRepository.findById(id) .filter(m -> !m.getBlind()) - .orElseThrow(() -> new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND)); + .orElseThrow(() -> new JwtException("해당 사용자를 찾을 수 없습니다.")); return new CustomUserDetails(member); } diff --git a/src/main/java/com/gamegoo/service/member/DeleteService.java b/src/main/java/com/gamegoo/service/member/DeleteService.java deleted file mode 100644 index 7fd3d0cc..00000000 --- a/src/main/java/com/gamegoo/service/member/DeleteService.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.gamegoo.service.member; - -import com.gamegoo.apiPayload.code.status.ErrorStatus; -import com.gamegoo.apiPayload.exception.handler.MemberHandler; -import com.gamegoo.domain.Member; -import com.gamegoo.repository.member.MemberRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.util.Optional; - -@Service -public class DeleteService { - private final MemberRepository memberRepository; - - @Autowired - - public DeleteService(MemberRepository memberRepository) { - this.memberRepository = memberRepository; - } - - public void deleteMember(Long userId) { - Optional optionalMember = memberRepository.findById(userId); - if (optionalMember.isPresent()) { - Member member = optionalMember.get(); - member.setBlind(true); - memberRepository.save(member); - } else { - throw new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND); - } - - } -} diff --git a/src/main/java/com/gamegoo/service/member/JoinService.java b/src/main/java/com/gamegoo/service/member/JoinService.java deleted file mode 100644 index f09127f0..00000000 --- a/src/main/java/com/gamegoo/service/member/JoinService.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.gamegoo.service.member; - -import com.gamegoo.domain.Member; -import com.gamegoo.domain.enums.LoginType; -import com.gamegoo.dto.member.JoinDTO; -import com.gamegoo.repository.member.MemberRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.stereotype.Service; - -@Service -public class JoinService { - - private final MemberRepository memberRepository; - private final BCryptPasswordEncoder bCryptPasswordEncoder; - - // 생성자 - @Autowired - public JoinService(MemberRepository memberRepository, BCryptPasswordEncoder bCryptPasswordEncoder) { - this.memberRepository = memberRepository; - this.bCryptPasswordEncoder = bCryptPasswordEncoder; - } - - // 회원가입 로직 - public void JoinMember(JoinDTO joinDTO) { - - // DTO로부터 데이터 받기 - String email = joinDTO.getEmail(); - String password = joinDTO.getPassword(); - // 중복 확인은 이메일 인증 코드 발급 API에서 진행 (로직이 이메일 인증 API -> 회원가입 API) - - // DB에 넣을 정보 설정 - Member member = Member.builder() - .email(email) - .password(bCryptPasswordEncoder.encode(password)) - .loginType(LoginType.GENERAL) - .profileImage("default") - .blind(false) - .build(); - - // DB에 저장 - memberRepository.save(member); - } -} diff --git a/src/main/java/com/gamegoo/service/member/PasswordService.java b/src/main/java/com/gamegoo/service/member/PasswordService.java index 05b7722f..ba030185 100644 --- a/src/main/java/com/gamegoo/service/member/PasswordService.java +++ b/src/main/java/com/gamegoo/service/member/PasswordService.java @@ -4,24 +4,19 @@ import com.gamegoo.apiPayload.exception.handler.MemberHandler; import com.gamegoo.domain.Member; import com.gamegoo.repository.member.MemberRepository; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.RequiredArgsConstructor; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; import java.util.Optional; @Service +@RequiredArgsConstructor public class PasswordService { private final MemberRepository memberRepository; private final BCryptPasswordEncoder bCryptPasswordEncoder; - @Autowired - public PasswordService(MemberRepository memberRepository, BCryptPasswordEncoder bCryptPasswordEncoder) { - this.memberRepository = memberRepository; - this.bCryptPasswordEncoder = bCryptPasswordEncoder; - } - public boolean checkPasswordById(Long userId, String password) { return memberRepository.findById(userId) .map(member -> bCryptPasswordEncoder.matches(password, member.getPassword())) diff --git a/src/main/java/com/gamegoo/service/member/PositionService.java b/src/main/java/com/gamegoo/service/member/PositionService.java deleted file mode 100644 index 263c3fb0..00000000 --- a/src/main/java/com/gamegoo/service/member/PositionService.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.gamegoo.service.member; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.gamegoo.apiPayload.ApiResponse; -import com.gamegoo.apiPayload.code.status.ErrorStatus; -import com.gamegoo.domain.Member; -import com.gamegoo.repository.member.MemberRepository; -import com.gamegoo.security.SecurityUtil; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.util.Optional; - -@Service -public class PositionService { - private final MemberRepository memberRepository; - private final HttpServletResponse response; - - @Autowired - public PositionService(MemberRepository memberRepository, HttpServletResponse response) { - this.memberRepository = memberRepository; - this.response = response; - } - - public void modifyPosition(int mainP, int subP) throws IOException { - Long userId = SecurityUtil.getCurrentUserId(); - ErrorStatus errorStatus = null; - - // 만약 mainP, subP 가 1~5의 값이 아닐 경우 - if (mainP <= 0 || subP <= 0 || mainP > 5 || subP > 5) { - errorStatus = ErrorStatus.POSITION_NOT_FOUND; - } - - Optional optionalMember = memberRepository.findById(userId); - - if (optionalMember.isPresent()) { - Member member = optionalMember.get(); - member.setMainPosition(mainP); - member.setSubPosition(subP); - memberRepository.save(member); - } else { - errorStatus = ErrorStatus.MEMBER_NOT_FOUND; - } - - if (errorStatus != null) { - ApiResponse apiResponse = ApiResponse.onFailure(errorStatus.getCode(), errorStatus.getMessage(), null); - - response.setStatus(errorStatus.getHttpStatus().value()); - response.setContentType("application/json"); - response.setCharacterEncoding("UTF-8"); - new ObjectMapper().writeValue(response.getWriter(), apiResponse); - - } - } - -} diff --git a/src/main/java/com/gamegoo/service/member/ProfileImageService.java b/src/main/java/com/gamegoo/service/member/ProfileImageService.java deleted file mode 100644 index b859aeb9..00000000 --- a/src/main/java/com/gamegoo/service/member/ProfileImageService.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.gamegoo.service.member; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.gamegoo.apiPayload.ApiResponse; -import com.gamegoo.apiPayload.code.status.ErrorStatus; -import com.gamegoo.domain.Member; -import com.gamegoo.repository.member.MemberRepository; -import com.gamegoo.security.SecurityUtil; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.util.Optional; - -@Service -public class ProfileImageService { - private final MemberRepository memberRepository; - private final HttpServletResponse response; - - @Autowired - public ProfileImageService(MemberRepository memberRepository, HttpServletResponse response) { - this.memberRepository = memberRepository; - this.response = response; - } - - public void modifyPosition(String profileImage) throws IOException { - Long userId = SecurityUtil.getCurrentUserId(); - ErrorStatus errorStatus = null; - - if (profileImage.length() > 30) { - errorStatus = ErrorStatus.PROFILE_IMAGE_BAD_REQUEST; - } else { - Optional optionalMember = memberRepository.findById(userId); - - if (optionalMember.isPresent()) { - Member member = optionalMember.get(); - member.setProfileImage(profileImage); - memberRepository.save(member); - } else { - errorStatus = ErrorStatus.MEMBER_NOT_FOUND; - } - } - - - if (errorStatus != null) { - ApiResponse apiResponse = ApiResponse.onFailure(errorStatus.getCode(), errorStatus.getMessage(), null); - - response.setStatus(errorStatus.getHttpStatus().value()); - response.setContentType("application/json"); - response.setCharacterEncoding("UTF-8"); - new ObjectMapper().writeValue(response.getWriter(), apiResponse); - - } - } -} diff --git a/src/main/java/com/gamegoo/service/member/MemberGameStyleService.java b/src/main/java/com/gamegoo/service/member/ProfileService.java similarity index 54% rename from src/main/java/com/gamegoo/service/member/MemberGameStyleService.java rename to src/main/java/com/gamegoo/service/member/ProfileService.java index 5bcb08d2..dbfdfb53 100644 --- a/src/main/java/com/gamegoo/service/member/MemberGameStyleService.java +++ b/src/main/java/com/gamegoo/service/member/ProfileService.java @@ -1,17 +1,17 @@ package com.gamegoo.service.member; - import com.fasterxml.jackson.databind.ObjectMapper; import com.gamegoo.apiPayload.ApiResponse; import com.gamegoo.apiPayload.code.status.ErrorStatus; +import com.gamegoo.apiPayload.exception.handler.MemberHandler; import com.gamegoo.domain.Member; import com.gamegoo.domain.gamestyle.GameStyle; import com.gamegoo.domain.gamestyle.MemberGameStyle; import com.gamegoo.repository.member.GameStyleRepository; import com.gamegoo.repository.member.MemberGameStyleRepository; import com.gamegoo.repository.member.MemberRepository; -import com.gamegoo.security.SecurityUtil; -import org.springframework.beans.factory.annotation.Autowired; +import com.gamegoo.util.SecurityUtil; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -23,26 +23,19 @@ import java.util.Set; @Service -public class MemberGameStyleService { - +@RequiredArgsConstructor +public class ProfileService { private final MemberRepository memberRepository; private final GameStyleRepository gameStyleRepository; private final MemberGameStyleRepository memberGameStyleRepository; private final HttpServletResponse response; - @Autowired - public MemberGameStyleService(MemberRepository memberRepository, GameStyleRepository gameStyleRepository, MemberGameStyleRepository memberGameStyleRepository, HttpServletResponse response) { - this.memberRepository = memberRepository; - this.gameStyleRepository = gameStyleRepository; - this.memberGameStyleRepository = memberGameStyleRepository; - this.response = response; - } @Transactional public void addMemberGameStyles(List gameStyles) throws IOException { Long userId = SecurityUtil.getCurrentUserId(); ErrorStatus errorStatus = null; - + Optional member = memberRepository.findById(userId); if (member.isEmpty()) { @@ -93,4 +86,77 @@ public void addMemberGameStyles(List gameStyles) throws IOException { } } } + + public void deleteMember(Long userId) { + Optional optionalMember = memberRepository.findById(userId); + if (optionalMember.isPresent()) { + Member member = optionalMember.get(); + member.setBlind(true); + memberRepository.save(member); + } else { + throw new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND); + } + + } + + public void modifyPosition(int mainP, int subP) throws IOException { + Long userId = SecurityUtil.getCurrentUserId(); + ErrorStatus errorStatus = null; + + // 만약 mainP, subP 가 1~5의 값이 아닐 경우 + if (mainP <= 0 || subP <= 0 || mainP > 5 || subP > 5) { + errorStatus = ErrorStatus.POSITION_NOT_FOUND; + } + + Optional optionalMember = memberRepository.findById(userId); + + if (optionalMember.isPresent()) { + Member member = optionalMember.get(); + member.setMainPosition(mainP); + member.setSubPosition(subP); + memberRepository.save(member); + } else { + errorStatus = ErrorStatus.MEMBER_NOT_FOUND; + } + + if (errorStatus != null) { + ApiResponse apiResponse = ApiResponse.onFailure(errorStatus.getCode(), errorStatus.getMessage(), null); + + response.setStatus(errorStatus.getHttpStatus().value()); + response.setContentType("application/json"); + response.setCharacterEncoding("UTF-8"); + new ObjectMapper().writeValue(response.getWriter(), apiResponse); + + } + } + + public void modifyProfileImage(String profileImage) throws IOException { + Long userId = SecurityUtil.getCurrentUserId(); + ErrorStatus errorStatus = null; + + if (profileImage.length() > 30) { + errorStatus = ErrorStatus.PROFILE_IMAGE_BAD_REQUEST; + } else { + Optional optionalMember = memberRepository.findById(userId); + + if (optionalMember.isPresent()) { + Member member = optionalMember.get(); + member.setProfileImage(profileImage); + memberRepository.save(member); + } else { + errorStatus = ErrorStatus.MEMBER_NOT_FOUND; + } + } + + + if (errorStatus != null) { + ApiResponse apiResponse = ApiResponse.onFailure(errorStatus.getCode(), errorStatus.getMessage(), null); + + response.setStatus(errorStatus.getHttpStatus().value()); + response.setContentType("application/json"); + response.setCharacterEncoding("UTF-8"); + new ObjectMapper().writeValue(response.getWriter(), apiResponse); + + } + } } diff --git a/src/main/java/com/gamegoo/security/RefreshTokenService.java b/src/main/java/com/gamegoo/service/member/RefreshTokenService.java similarity index 80% rename from src/main/java/com/gamegoo/security/RefreshTokenService.java rename to src/main/java/com/gamegoo/service/member/RefreshTokenService.java index 012d8420..14b4d64b 100644 --- a/src/main/java/com/gamegoo/security/RefreshTokenService.java +++ b/src/main/java/com/gamegoo/service/member/RefreshTokenService.java @@ -1,18 +1,16 @@ -package com.gamegoo.security; +package com.gamegoo.service.member; import com.gamegoo.domain.Member; -import com.gamegoo.jwt.JWTUtil; import com.gamegoo.repository.member.MemberRepository; -import org.springframework.beans.factory.annotation.Autowired; +import com.gamegoo.util.JWTUtil; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @Service +@RequiredArgsConstructor public class RefreshTokenService { - @Autowired private MemberRepository memberRepository; - - @Autowired private JWTUtil jwtUtil; public void saveRefreshToken(Long id, String refresh_token) { diff --git a/src/main/java/com/gamegoo/security/CodeGeneratorUtil.java b/src/main/java/com/gamegoo/util/CodeGeneratorUtil.java similarity index 95% rename from src/main/java/com/gamegoo/security/CodeGeneratorUtil.java rename to src/main/java/com/gamegoo/util/CodeGeneratorUtil.java index ce5f972a..d145fff0 100644 --- a/src/main/java/com/gamegoo/security/CodeGeneratorUtil.java +++ b/src/main/java/com/gamegoo/util/CodeGeneratorUtil.java @@ -1,4 +1,4 @@ -package com.gamegoo.security; +package com.gamegoo.util; import java.security.SecureRandom; diff --git a/src/main/java/com/gamegoo/jwt/JWTUtil.java b/src/main/java/com/gamegoo/util/JWTUtil.java similarity index 97% rename from src/main/java/com/gamegoo/jwt/JWTUtil.java rename to src/main/java/com/gamegoo/util/JWTUtil.java index 6c46c387..b9a09467 100644 --- a/src/main/java/com/gamegoo/jwt/JWTUtil.java +++ b/src/main/java/com/gamegoo/util/JWTUtil.java @@ -1,4 +1,4 @@ -package com.gamegoo.jwt; +package com.gamegoo.util; import io.jsonwebtoken.Jwts; import org.springframework.beans.factory.annotation.Value; diff --git a/src/main/java/com/gamegoo/security/SecurityUtil.java b/src/main/java/com/gamegoo/util/SecurityUtil.java similarity index 88% rename from src/main/java/com/gamegoo/security/SecurityUtil.java rename to src/main/java/com/gamegoo/util/SecurityUtil.java index 8fbd8bb0..c1ccdada 100644 --- a/src/main/java/com/gamegoo/security/SecurityUtil.java +++ b/src/main/java/com/gamegoo/util/SecurityUtil.java @@ -1,5 +1,6 @@ -package com.gamegoo.security; +package com.gamegoo.util; +import com.gamegoo.security.CustomUserDetails; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; From dd3b30da151a772ced0877bd969200de81f317db Mon Sep 17 00:00:00 2001 From: Rimi Date: Sat, 29 Jun 2024 16:58:51 +0900 Subject: [PATCH 06/11] =?UTF-8?q?:recycle:=20[Refactor]=20Member=20API=20R?= =?UTF-8?q?esponse=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apiPayload/code/status/ErrorStatus.java | 6 +- .../controller/member/AuthController.java | 8 +- .../controller/member/PasswordController.java | 8 +- .../controller/member/ProfileController.java | 27 ++-- .../member/MemberGameStyleRepository.java | 4 +- .../gamegoo/service/member/AuthService.java | 25 ++-- .../service/member/PasswordService.java | 20 ++- .../service/member/ProfileService.java | 118 +++++------------- 8 files changed, 74 insertions(+), 142 deletions(-) diff --git a/src/main/java/com/gamegoo/apiPayload/code/status/ErrorStatus.java b/src/main/java/com/gamegoo/apiPayload/code/status/ErrorStatus.java index 65a9d2c4..1d491cd8 100644 --- a/src/main/java/com/gamegoo/apiPayload/code/status/ErrorStatus.java +++ b/src/main/java/com/gamegoo/apiPayload/code/status/ErrorStatus.java @@ -37,7 +37,11 @@ public enum ErrorStatus implements BaseErrorCode { POSITION_NOT_FOUND(HttpStatus.NOT_FOUND, "POSITION404", "해당 Position을 찾을 수 없습니다."), // Profile_Image 관련 에러 - PROFILE_IMAGE_BAD_REQUEST(HttpStatus.BAD_REQUEST, "PROFILE_IMAGE_400", "profile_image가 30자를 초과했습니다."); + PROFILE_IMAGE_BAD_REQUEST(HttpStatus.BAD_REQUEST, "PROFILE_IMAGE_400", "profile_image가 30자를 초과했습니다."), + + // Email 인증 관련 에러 + EMAIL_SEND_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "EMAIL500", "이메일 전송 도중, 에러가 발생했습니다."); + private final HttpStatus httpStatus; private final String code; private final String message; diff --git a/src/main/java/com/gamegoo/controller/member/AuthController.java b/src/main/java/com/gamegoo/controller/member/AuthController.java index dc5f1a40..e42588c3 100644 --- a/src/main/java/com/gamegoo/controller/member/AuthController.java +++ b/src/main/java/com/gamegoo/controller/member/AuthController.java @@ -12,8 +12,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import java.io.IOException; - @RestController @RequiredArgsConstructor @RequestMapping("/api/member") @@ -24,15 +22,13 @@ public class AuthController { @PostMapping("/join") @Operation(summary = "회원가입 API 입니다.", description = "API for join") public ApiResponse joinMember(@RequestBody JoinDTO joinDTO) { - System.out.println(joinDTO.getPassword()); - System.out.println(joinDTO.getEmail()); authService.JoinMember(joinDTO); - return ApiResponse.onSuccess(null); + return ApiResponse.onSuccess("회원가입에 성공했습니다."); } @PostMapping("/email") @Operation(summary = "이메일 인증코드 전송 API 입니다.", description = "API for email verification") - public ApiResponse verifyEmail(@RequestBody EmailDTO emailDTO) throws IOException { + public ApiResponse verifyEmail(@RequestBody EmailDTO emailDTO) { String emailAddress = emailDTO.getEmail_address(); String code = authService.verifyEmail(emailAddress); return ApiResponse.onSuccess(code); diff --git a/src/main/java/com/gamegoo/controller/member/PasswordController.java b/src/main/java/com/gamegoo/controller/member/PasswordController.java index 2bd4ede7..b7fffb1a 100644 --- a/src/main/java/com/gamegoo/controller/member/PasswordController.java +++ b/src/main/java/com/gamegoo/controller/member/PasswordController.java @@ -1,6 +1,8 @@ package com.gamegoo.controller.member; import com.gamegoo.apiPayload.ApiResponse; +import com.gamegoo.apiPayload.code.status.ErrorStatus; +import com.gamegoo.apiPayload.exception.handler.MemberHandler; import com.gamegoo.dto.member.PasswordDTO; import com.gamegoo.service.member.PasswordService; import com.gamegoo.util.SecurityUtil; @@ -27,9 +29,9 @@ public ApiResponse checkPassword(@RequestBody PasswordDTO passwordDTO) { boolean isPasswordValid = passwordService.checkPasswordById(currentUserId, passwordDTO.getPassword()); //request body에 있는 password와 currentUserId를 전달 if (isPasswordValid) { - return ApiResponse.onSuccess(null); + return ApiResponse.onSuccess("비밀번호가 일치합니다."); } else { - return ApiResponse.onFailure("PASSWORD_INVALID", "비밀번호가 불일치합니다.", null); + throw new MemberHandler(ErrorStatus.PASSWORD_INVALID); } } @@ -40,7 +42,7 @@ public ApiResponse resetPassword(@RequestBody PasswordDTO passwordDTO) { passwordService.updatePassword(currentUserId, passwordDTO.getPassword()); - return ApiResponse.onSuccess(null); + return ApiResponse.onSuccess("비밀번호 재설정을 완료했습니다."); } diff --git a/src/main/java/com/gamegoo/controller/member/ProfileController.java b/src/main/java/com/gamegoo/controller/member/ProfileController.java index 995e48ef..37d42b44 100644 --- a/src/main/java/com/gamegoo/controller/member/ProfileController.java +++ b/src/main/java/com/gamegoo/controller/member/ProfileController.java @@ -1,20 +1,15 @@ package com.gamegoo.controller.member; import com.gamegoo.apiPayload.ApiResponse; -import com.gamegoo.apiPayload.code.status.ErrorStatus; -import com.gamegoo.apiPayload.exception.handler.MemberHandler; import com.gamegoo.dto.member.GameStyleDTO; import com.gamegoo.dto.member.PositionDTO; import com.gamegoo.dto.member.ProfileImageDTO; import com.gamegoo.service.member.ProfileService; -import com.gamegoo.util.SecurityUtil; import io.swagger.v3.oas.annotations.Operation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; -import java.io.IOException; - @RestController @RequiredArgsConstructor @RequestMapping("/api/member") @@ -24,38 +19,34 @@ public class ProfileController { @PutMapping("/gamestyle") @Operation(summary = "gamestyle 추가 및 수정 API 입니다.", description = "API for Gamestyle addition and modification ") - public ApiResponse addGameStyle(@RequestBody GameStyleDTO gameStyleDTO) throws IOException { + public ApiResponse addGameStyle(@RequestBody GameStyleDTO gameStyleDTO) { profileService.addMemberGameStyles(gameStyleDTO.getGamestyle()); - return ApiResponse.onSuccess(null); + return ApiResponse.onSuccess("게임 스타일 수정이 완료되었습니다."); } @PutMapping("/position") @Operation(summary = "주/부 포지션 수정 API 입니다.", description = "API for Main/Sub Position Modification") - public ApiResponse modifyPosition(@RequestBody PositionDTO positionDTO) throws IOException { + public ApiResponse modifyPosition(@RequestBody PositionDTO positionDTO) { int mainP = positionDTO.getMainP(); int subP = positionDTO.getSubP(); profileService.modifyPosition(mainP, subP); - return ApiResponse.onSuccess(null); + return ApiResponse.onSuccess("포지션 수정이 완료되었습니다. "); } @PutMapping("/profile_image") @Operation(summary = "프로필 이미지 수정 API 입니다.", description = "API for Profile Image Modification") - public ApiResponse modifyPosition(@RequestBody ProfileImageDTO profileImageDTO) throws IOException { + public ApiResponse modifyPosition(@RequestBody ProfileImageDTO profileImageDTO) { String profileImage = profileImageDTO.getProfile_image(); profileService.modifyProfileImage(profileImage); - return ApiResponse.onSuccess(null); + return ApiResponse.onSuccess("프로필 이미지 수정이 완료되었습니다."); } @DeleteMapping("") @Operation(summary = "회원 탈퇴 API 입니다.", description = "API for Member") public ApiResponse blindMember() { - Long userId = SecurityUtil.getCurrentUserId(); //헤더에 있는 jwt 토큰에서 id를 가져오는 코드 - try { - profileService.deleteMember(userId); - return ApiResponse.onSuccess(null); - } catch (Exception e) { - throw new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND); - } + profileService.deleteMember(); + return ApiResponse.onSuccess("탈퇴처리가 완료되었습니다."); + } } diff --git a/src/main/java/com/gamegoo/repository/member/MemberGameStyleRepository.java b/src/main/java/com/gamegoo/repository/member/MemberGameStyleRepository.java index 308d05d3..60db43b9 100644 --- a/src/main/java/com/gamegoo/repository/member/MemberGameStyleRepository.java +++ b/src/main/java/com/gamegoo/repository/member/MemberGameStyleRepository.java @@ -9,7 +9,7 @@ import java.util.Optional; public interface MemberGameStyleRepository extends JpaRepository { - Optional findByMemberAndGameStyle(Optional member, Optional gameStyle); + Optional findByMemberAndGameStyle(Member member, GameStyle gameStyle); - List findByMember(Optional member); + List findByMember(Member member); } diff --git a/src/main/java/com/gamegoo/service/member/AuthService.java b/src/main/java/com/gamegoo/service/member/AuthService.java index b63aad16..72c932eb 100644 --- a/src/main/java/com/gamegoo/service/member/AuthService.java +++ b/src/main/java/com/gamegoo/service/member/AuthService.java @@ -1,8 +1,7 @@ package com.gamegoo.service.member; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.gamegoo.apiPayload.ApiResponse; import com.gamegoo.apiPayload.code.status.ErrorStatus; +import com.gamegoo.apiPayload.exception.handler.MemberHandler; import com.gamegoo.domain.Member; import com.gamegoo.domain.enums.LoginType; import com.gamegoo.dto.member.JoinDTO; @@ -16,9 +15,6 @@ import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.util.Optional; @Service @RequiredArgsConstructor @@ -26,7 +22,6 @@ public class AuthService { private final MemberRepository memberRepository; private final BCryptPasswordEncoder bCryptPasswordEncoder; private final JavaMailSender javaMailSender; - private final HttpServletResponse response; // 회원가입 로직 public void JoinMember(JoinDTO joinDTO) { @@ -50,17 +45,11 @@ public void JoinMember(JoinDTO joinDTO) { } //이메일 인증 및 전송 - public String verifyEmail(String email) throws IOException { + public String verifyEmail(String email) { // 중복 확인하기 - Optional byEmail = memberRepository.findByEmail(email); - if (byEmail.isPresent()) { - ErrorStatus errorStatus = ErrorStatus.MEMBER_CONFLICT; - ApiResponse apiResponse = ApiResponse.onFailure(errorStatus.getCode(), errorStatus.getMessage(), null); - - response.setStatus(errorStatus.getHttpStatus().value()); - response.setContentType("application/json"); - response.setCharacterEncoding("UTF-8"); - new ObjectMapper().writeValue(response.getWriter(), apiResponse); + boolean isPresent = memberRepository.findByEmail(email).isPresent(); + if (isPresent) { + throw new MemberHandler(ErrorStatus.MEMBER_CONFLICT); } // 랜덤 코드 생성하기 @@ -80,8 +69,10 @@ public String verifyEmail(String email) throws IOException { javaMailSender.send(message); } catch (MessagingException e) { - throw new RuntimeException(e); + throw new MemberHandler(ErrorStatus.EMAIL_SEND_ERROR); } + + // 인증 번호 반환 return certificationNumber; } diff --git a/src/main/java/com/gamegoo/service/member/PasswordService.java b/src/main/java/com/gamegoo/service/member/PasswordService.java index ba030185..028fe536 100644 --- a/src/main/java/com/gamegoo/service/member/PasswordService.java +++ b/src/main/java/com/gamegoo/service/member/PasswordService.java @@ -8,8 +8,6 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; -import java.util.Optional; - @Service @RequiredArgsConstructor public class PasswordService { @@ -20,17 +18,17 @@ public class PasswordService { public boolean checkPasswordById(Long userId, String password) { return memberRepository.findById(userId) .map(member -> bCryptPasswordEncoder.matches(password, member.getPassword())) - .orElse(false); + .orElseThrow(() -> new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND)); } public void updatePassword(Long userId, String newPassword) { - Optional optionalMember = memberRepository.findById(userId); - if (optionalMember.isPresent()) { - Member member = optionalMember.get(); - member.setPassword(bCryptPasswordEncoder.encode(newPassword)); - memberRepository.save(member); - } else { - throw new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND); - } + // jwt 토큰으로 멤버 찾기 + Member member = memberRepository.findById(userId) + .orElseThrow(() -> new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND)); + + // 비밀번호 재설정 + member.setPassword(bCryptPasswordEncoder.encode(newPassword)); + memberRepository.save(member); } + } diff --git a/src/main/java/com/gamegoo/service/member/ProfileService.java b/src/main/java/com/gamegoo/service/member/ProfileService.java index dbfdfb53..1ea2b3bc 100644 --- a/src/main/java/com/gamegoo/service/member/ProfileService.java +++ b/src/main/java/com/gamegoo/service/member/ProfileService.java @@ -1,7 +1,5 @@ package com.gamegoo.service.member; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.gamegoo.apiPayload.ApiResponse; import com.gamegoo.apiPayload.code.status.ErrorStatus; import com.gamegoo.apiPayload.exception.handler.MemberHandler; import com.gamegoo.domain.Member; @@ -15,8 +13,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; import java.util.HashSet; import java.util.List; import java.util.Optional; @@ -28,19 +24,16 @@ public class ProfileService { private final MemberRepository memberRepository; private final GameStyleRepository gameStyleRepository; private final MemberGameStyleRepository memberGameStyleRepository; - private final HttpServletResponse response; @Transactional - public void addMemberGameStyles(List gameStyles) throws IOException { + public void addMemberGameStyles(List gameStyles) { + Long userId = SecurityUtil.getCurrentUserId(); - ErrorStatus errorStatus = null; - Optional member = memberRepository.findById(userId); + Member member = memberRepository.findById(userId) + .orElseThrow(() -> new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND)); - if (member.isEmpty()) { - errorStatus = ErrorStatus.MEMBER_NOT_FOUND; - } // 요청된 game style 목록을 Set으로 변환 Set requestedGameStyles = new HashSet<>(gameStyles); @@ -55,108 +48,65 @@ public void addMemberGameStyles(List gameStyles) throws IOException { // 요청 중에 repository에 없는 항목을 추가 for (String styleName : gameStyles) { - Optional gameStyle = gameStyleRepository.findByStyleName(styleName); - if (gameStyle.isEmpty()) { - errorStatus = ErrorStatus.GAMESTYLE_NOT_FOUND; - } - - // errorStatus가 null이 아닌 경우 error Response - if (errorStatus != null) { - ApiResponse apiResponse = ApiResponse.onFailure(errorStatus.getCode(), errorStatus.getMessage(), null); - - response.setStatus(errorStatus.getHttpStatus().value()); - response.setContentType("application/json"); - response.setCharacterEncoding("UTF-8"); - new ObjectMapper().writeValue(response.getWriter(), apiResponse); - } + // 요청에 해당하는 gamestyle 테이블에서 찾기 + GameStyle gameStyle = gameStyleRepository.findByStyleName(styleName) + .orElseThrow(() -> new MemberHandler(ErrorStatus.GAMESTYLE_NOT_FOUND)); + // 있는지 검사하기 Optional existingMemberGameStyle = memberGameStyleRepository.findByMemberAndGameStyle(member, gameStyle); // 없을 경우 if (existingMemberGameStyle.isEmpty()) { - if (member.isPresent() && gameStyle.isPresent()) { - MemberGameStyle memberGameStyle = MemberGameStyle.builder() - .member(member.get()) - .gameStyle(gameStyle.get()) - .build(); - memberGameStyleRepository.save(memberGameStyle); - } - + MemberGameStyle memberGameStyle = MemberGameStyle.builder() + .member(member) + .gameStyle(gameStyle) + .build(); + memberGameStyleRepository.save(memberGameStyle); } } } - public void deleteMember(Long userId) { - Optional optionalMember = memberRepository.findById(userId); - if (optionalMember.isPresent()) { - Member member = optionalMember.get(); - member.setBlind(true); - memberRepository.save(member); - } else { - throw new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND); - } + public void deleteMember() { + Long userId = SecurityUtil.getCurrentUserId(); + Member member = memberRepository.findById(userId) + .orElseThrow(() -> new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND)); + + // Blind 처리 + member.setBlind(true); + memberRepository.save(member); } - public void modifyPosition(int mainP, int subP) throws IOException { + public void modifyPosition(int mainP, int subP) { Long userId = SecurityUtil.getCurrentUserId(); - ErrorStatus errorStatus = null; // 만약 mainP, subP 가 1~5의 값이 아닐 경우 if (mainP <= 0 || subP <= 0 || mainP > 5 || subP > 5) { - errorStatus = ErrorStatus.POSITION_NOT_FOUND; - } - - Optional optionalMember = memberRepository.findById(userId); - - if (optionalMember.isPresent()) { - Member member = optionalMember.get(); - member.setMainPosition(mainP); - member.setSubPosition(subP); - memberRepository.save(member); - } else { - errorStatus = ErrorStatus.MEMBER_NOT_FOUND; + throw new MemberHandler(ErrorStatus.POSITION_NOT_FOUND); } - if (errorStatus != null) { - ApiResponse apiResponse = ApiResponse.onFailure(errorStatus.getCode(), errorStatus.getMessage(), null); + Member member = memberRepository.findById(userId) + .orElseThrow(() -> new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND)); - response.setStatus(errorStatus.getHttpStatus().value()); - response.setContentType("application/json"); - response.setCharacterEncoding("UTF-8"); - new ObjectMapper().writeValue(response.getWriter(), apiResponse); - - } + member.setMainPosition(mainP); + member.setSubPosition(subP); + memberRepository.save(member); } - public void modifyProfileImage(String profileImage) throws IOException { + public void modifyProfileImage(String profileImage) { Long userId = SecurityUtil.getCurrentUserId(); - ErrorStatus errorStatus = null; if (profileImage.length() > 30) { - errorStatus = ErrorStatus.PROFILE_IMAGE_BAD_REQUEST; - } else { - Optional optionalMember = memberRepository.findById(userId); - - if (optionalMember.isPresent()) { - Member member = optionalMember.get(); - member.setProfileImage(profileImage); - memberRepository.save(member); - } else { - errorStatus = ErrorStatus.MEMBER_NOT_FOUND; - } + throw new MemberHandler(ErrorStatus.PROFILE_IMAGE_BAD_REQUEST); } + Member member = memberRepository.findById(userId) + .orElseThrow(() -> new MemberHandler(ErrorStatus.MEMBER_NOT_FOUND)); - if (errorStatus != null) { - ApiResponse apiResponse = ApiResponse.onFailure(errorStatus.getCode(), errorStatus.getMessage(), null); + member.setProfileImage(profileImage); + memberRepository.save(member); - response.setStatus(errorStatus.getHttpStatus().value()); - response.setContentType("application/json"); - response.setCharacterEncoding("UTF-8"); - new ObjectMapper().writeValue(response.getWriter(), apiResponse); - } } } From 60ab4517f7daf4f294f285ecdf6844e4229e84c4 Mon Sep 17 00:00:00 2001 From: Rimi Date: Sat, 29 Jun 2024 17:00:28 +0900 Subject: [PATCH 07/11] =?UTF-8?q?:sparkles:=20[feat]=20=ED=9A=8C=EC=9B=90?= =?UTF-8?q?=EA=B0=80=EC=9E=85=20API=EC=97=90=20=EC=A4=91=EB=B3=B5=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/gamegoo/service/member/AuthService.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/gamegoo/service/member/AuthService.java b/src/main/java/com/gamegoo/service/member/AuthService.java index 72c932eb..1e8548ce 100644 --- a/src/main/java/com/gamegoo/service/member/AuthService.java +++ b/src/main/java/com/gamegoo/service/member/AuthService.java @@ -29,7 +29,12 @@ public void JoinMember(JoinDTO joinDTO) { // DTO로부터 데이터 받기 String email = joinDTO.getEmail(); String password = joinDTO.getPassword(); - // 중복 확인은 이메일 인증 코드 발급 API에서 진행 (로직이 이메일 인증 API -> 회원가입 API) + + // 중복 확인하기 + boolean isPresent = memberRepository.findByEmail(email).isPresent(); + if (isPresent) { + throw new MemberHandler(ErrorStatus.MEMBER_CONFLICT); + } // DB에 넣을 정보 설정 Member member = Member.builder() From 8c40463291171d27f36cd8f8208ed2cbb42eb4ab Mon Sep 17 00:00:00 2001 From: Rimi Date: Sat, 29 Jun 2024 17:52:46 +0900 Subject: [PATCH 08/11] =?UTF-8?q?:sparkles:=20[feat]=20=EC=9D=B8=EC=A6=9D?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EA=B2=80=EC=A6=9D=20API=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20=EB=B0=8F=20EmailVerifyRecord=20=EC=97=94=ED=8B=B0?= =?UTF-8?q?=ED=8B=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apiPayload/code/status/ErrorStatus.java | 4 +- .../controller/member/AuthController.java | 22 +++++++--- .../com/gamegoo/domain/EmailVerifyRecord.java | 27 ++++++++++++ .../com/gamegoo/dto/member/EmailCodeDTO.java | 11 +++++ .../java/com/gamegoo/dto/member/EmailDTO.java | 2 +- .../member/EmailVerifyRecordRepository.java | 10 +++++ .../gamegoo/service/member/AuthService.java | 44 ++++++++++++++++--- 7 files changed, 105 insertions(+), 15 deletions(-) create mode 100644 src/main/java/com/gamegoo/domain/EmailVerifyRecord.java create mode 100644 src/main/java/com/gamegoo/dto/member/EmailCodeDTO.java create mode 100644 src/main/java/com/gamegoo/repository/member/EmailVerifyRecordRepository.java diff --git a/src/main/java/com/gamegoo/apiPayload/code/status/ErrorStatus.java b/src/main/java/com/gamegoo/apiPayload/code/status/ErrorStatus.java index 1d491cd8..99c2b6bd 100644 --- a/src/main/java/com/gamegoo/apiPayload/code/status/ErrorStatus.java +++ b/src/main/java/com/gamegoo/apiPayload/code/status/ErrorStatus.java @@ -40,7 +40,9 @@ public enum ErrorStatus implements BaseErrorCode { PROFILE_IMAGE_BAD_REQUEST(HttpStatus.BAD_REQUEST, "PROFILE_IMAGE_400", "profile_image가 30자를 초과했습니다."), // Email 인증 관련 에러 - EMAIL_SEND_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "EMAIL500", "이메일 전송 도중, 에러가 발생했습니다."); + EMAIL_SEND_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "EMAIL500", "이메일 전송 도중, 에러가 발생했습니다."), + EMAIL_NOT_FOUND(HttpStatus.NOT_FOUND, "EMAIL404", "해당 이메일을 찾을 수 없습니다."), + EMAIL_INVALID(HttpStatus.BAD_REQUEST, "EMAIL400", "인증 코드가 불일치합니다."); private final HttpStatus httpStatus; private final String code; diff --git a/src/main/java/com/gamegoo/controller/member/AuthController.java b/src/main/java/com/gamegoo/controller/member/AuthController.java index e42588c3..f868d0ea 100644 --- a/src/main/java/com/gamegoo/controller/member/AuthController.java +++ b/src/main/java/com/gamegoo/controller/member/AuthController.java @@ -1,6 +1,7 @@ package com.gamegoo.controller.member; import com.gamegoo.apiPayload.ApiResponse; +import com.gamegoo.dto.member.EmailCodeDTO; import com.gamegoo.dto.member.EmailDTO; import com.gamegoo.dto.member.JoinDTO; import com.gamegoo.service.member.AuthService; @@ -22,15 +23,24 @@ public class AuthController { @PostMapping("/join") @Operation(summary = "회원가입 API 입니다.", description = "API for join") public ApiResponse joinMember(@RequestBody JoinDTO joinDTO) { - authService.JoinMember(joinDTO); + authService.joinMember(joinDTO); return ApiResponse.onSuccess("회원가입에 성공했습니다."); } - @PostMapping("/email") - @Operation(summary = "이메일 인증코드 전송 API 입니다.", description = "API for email verification") - public ApiResponse verifyEmail(@RequestBody EmailDTO emailDTO) { - String emailAddress = emailDTO.getEmail_address(); - String code = authService.verifyEmail(emailAddress); + @PostMapping("/email/send") + @Operation(summary = "이메일 인증코드 전송 API 입니다.", description = "API for sending email") + public ApiResponse sendEmail(@RequestBody EmailDTO emailDTO) { + String email = emailDTO.getEmail(); + String code = authService.sendEmail(email); return ApiResponse.onSuccess(code); } + + @PostMapping("/email/verify") + @Operation(summary = "이메일 인증코드 검증 API 입니다.", description = "API for email verification") + public ApiResponse verifyEmail(@RequestBody EmailCodeDTO emailCodeDTO) { + String email = emailCodeDTO.getEmail(); + String code = emailCodeDTO.getCode(); + authService.verifyEmail(email, code); + return ApiResponse.onSuccess("성공했습니다."); + } } diff --git a/src/main/java/com/gamegoo/domain/EmailVerifyRecord.java b/src/main/java/com/gamegoo/domain/EmailVerifyRecord.java new file mode 100644 index 00000000..603b4fd3 --- /dev/null +++ b/src/main/java/com/gamegoo/domain/EmailVerifyRecord.java @@ -0,0 +1,27 @@ +package com.gamegoo.domain; + +import com.gamegoo.domain.common.BaseDateTimeEntity; +import lombok.*; + +import javax.persistence.*; + +@Entity +@Table(name = "EmailVerifyRecord") +@Getter +@Builder +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +public class EmailVerifyRecord extends BaseDateTimeEntity { + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "record_id") + private Long id; + + @Column(name = "email", nullable = false, length = 100) + private String email; + + @Column(name = "code", nullable = false, length = 10) + private String code; + + +} diff --git a/src/main/java/com/gamegoo/dto/member/EmailCodeDTO.java b/src/main/java/com/gamegoo/dto/member/EmailCodeDTO.java new file mode 100644 index 00000000..7e87214c --- /dev/null +++ b/src/main/java/com/gamegoo/dto/member/EmailCodeDTO.java @@ -0,0 +1,11 @@ +package com.gamegoo.dto.member; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class EmailCodeDTO { + private String email; + private String code; +} diff --git a/src/main/java/com/gamegoo/dto/member/EmailDTO.java b/src/main/java/com/gamegoo/dto/member/EmailDTO.java index 9a59e033..fa4f7059 100644 --- a/src/main/java/com/gamegoo/dto/member/EmailDTO.java +++ b/src/main/java/com/gamegoo/dto/member/EmailDTO.java @@ -6,5 +6,5 @@ @Getter @Setter public class EmailDTO { - private String email_address; + private String email; } diff --git a/src/main/java/com/gamegoo/repository/member/EmailVerifyRecordRepository.java b/src/main/java/com/gamegoo/repository/member/EmailVerifyRecordRepository.java new file mode 100644 index 00000000..9dba10f3 --- /dev/null +++ b/src/main/java/com/gamegoo/repository/member/EmailVerifyRecordRepository.java @@ -0,0 +1,10 @@ +package com.gamegoo.repository.member; + +import com.gamegoo.domain.EmailVerifyRecord; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface EmailVerifyRecordRepository extends JpaRepository { + Optional findByEmailOrderByUpdatedAtDesc(String email); +} diff --git a/src/main/java/com/gamegoo/service/member/AuthService.java b/src/main/java/com/gamegoo/service/member/AuthService.java index 1e8548ce..f7f77d98 100644 --- a/src/main/java/com/gamegoo/service/member/AuthService.java +++ b/src/main/java/com/gamegoo/service/member/AuthService.java @@ -2,9 +2,11 @@ import com.gamegoo.apiPayload.code.status.ErrorStatus; import com.gamegoo.apiPayload.exception.handler.MemberHandler; +import com.gamegoo.domain.EmailVerifyRecord; import com.gamegoo.domain.Member; import com.gamegoo.domain.enums.LoginType; import com.gamegoo.dto.member.JoinDTO; +import com.gamegoo.repository.member.EmailVerifyRecordRepository; import com.gamegoo.repository.member.MemberRepository; import com.gamegoo.util.CodeGeneratorUtil; import lombok.RequiredArgsConstructor; @@ -20,11 +22,12 @@ @RequiredArgsConstructor public class AuthService { private final MemberRepository memberRepository; + private final EmailVerifyRecordRepository emailVerifyRecordRepository; private final BCryptPasswordEncoder bCryptPasswordEncoder; private final JavaMailSender javaMailSender; // 회원가입 로직 - public void JoinMember(JoinDTO joinDTO) { + public void joinMember(JoinDTO joinDTO) { // DTO로부터 데이터 받기 String email = joinDTO.getEmail(); @@ -49,8 +52,8 @@ public void JoinMember(JoinDTO joinDTO) { memberRepository.save(member); } - //이메일 인증 및 전송 - public String verifyEmail(String email) { + //이메일 인증코드 전송 + public String sendEmail(String email) { // 중복 확인하기 boolean isPresent = memberRepository.findByEmail(email).isPresent(); if (isPresent) { @@ -60,7 +63,36 @@ public String verifyEmail(String email) { // 랜덤 코드 생성하기 String certificationNumber = CodeGeneratorUtil.generateRandomCode(); - // 메일 보내기 + // 메일 전송하기 + sendEmailInternal(email, certificationNumber); + + // 메일 전송 기록 DB에 저장하기 + EmailVerifyRecord emailVerifyRecord = EmailVerifyRecord.builder() + .email(email) + .code(certificationNumber) + .build(); + + emailVerifyRecordRepository.save(emailVerifyRecord); + + // 인증 번호 반환 + return certificationNumber; + } + + // 이메일 인증코드 검증 + public void verifyEmail(String email, String code) { + // 이메일로 보낸 인증 코드 중 가장 최근의 데이터를 불러옴 + EmailVerifyRecord emailVerifyRecord = emailVerifyRecordRepository.findByEmailOrderByUpdatedAtDesc(email) + // 해당 이메일이 없을 경우 + .orElseThrow(() -> new MemberHandler(ErrorStatus.EMAIL_NOT_FOUND)); + + // 인증 코드가 틀릴 경우 + if (!emailVerifyRecord.getCode().equals(code)) { + throw new MemberHandler(ErrorStatus.EMAIL_INVALID); + } + } + + // 메일 전송하는 메소드 + private void sendEmailInternal(String email, String certificationNumber) { try { MimeMessage message = javaMailSender.createMimeMessage(); MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(message, true); @@ -76,11 +108,9 @@ public String verifyEmail(String email) { } catch (MessagingException e) { throw new MemberHandler(ErrorStatus.EMAIL_SEND_ERROR); } - - // 인증 번호 반환 - return certificationNumber; } + // 메일 내용 private String getCertificationMessage(String certificationNumber) { String certificationMessage = ""; certificationMessage += "

[GAMEGOO 인증메일]

"; From 76237eab61ad66258b1605f83bb84d6496dc57f0 Mon Sep 17 00:00:00 2001 From: Rimi Date: Sat, 29 Jun 2024 19:19:23 +0900 Subject: [PATCH 09/11] =?UTF-8?q?:bug:=20[Fix]=20JWT=20Filter=20=ED=86=A0?= =?UTF-8?q?=ED=81=B0=EC=9D=B4=20=EC=97=86=EC=9D=84=20=EA=B2=BD=EC=9A=B0=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gamegoo/apiPayload/code/status/ErrorStatus.java | 1 + .../exception/handler/JWTExceptionHandlerFilter.java | 2 ++ src/main/java/com/gamegoo/config/SecurityConfig.java | 4 ++-- .../com/gamegoo/controller/member/AuthController.java | 9 ++++++--- src/main/java/com/gamegoo/domain/EmailVerifyRecord.java | 1 - src/main/java/com/gamegoo/filter/JWTFilter.java | 5 +---- .../java/com/gamegoo/service/member/AuthService.java | 5 +---- src/main/resources/application.yml | 2 +- 8 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/gamegoo/apiPayload/code/status/ErrorStatus.java b/src/main/java/com/gamegoo/apiPayload/code/status/ErrorStatus.java index 99c2b6bd..c2e71662 100644 --- a/src/main/java/com/gamegoo/apiPayload/code/status/ErrorStatus.java +++ b/src/main/java/com/gamegoo/apiPayload/code/status/ErrorStatus.java @@ -29,6 +29,7 @@ public enum ErrorStatus implements BaseErrorCode { // JWT 관련 에러 TOKEN_EXPIRED(HttpStatus.UNAUTHORIZED, "JWT401", "jwt 토큰이 만료되었습니다."), INVALID_TOKEN(HttpStatus.BAD_REQUEST, "JWT400", "유효하지 않은 jwt 토큰입니다."), + TOKEN_NULL(HttpStatus.NOT_FOUND, "JWT404", "JWT 토큰이 없습니다."), // GameStyle 관련 에러 GAMESTYLE_NOT_FOUND(HttpStatus.NOT_FOUND, "GAMESTYLE404", "해당 게임 스타일을 찾을 수 없습니다."), diff --git a/src/main/java/com/gamegoo/apiPayload/exception/handler/JWTExceptionHandlerFilter.java b/src/main/java/com/gamegoo/apiPayload/exception/handler/JWTExceptionHandlerFilter.java index 654b896d..220fb0e5 100644 --- a/src/main/java/com/gamegoo/apiPayload/exception/handler/JWTExceptionHandlerFilter.java +++ b/src/main/java/com/gamegoo/apiPayload/exception/handler/JWTExceptionHandlerFilter.java @@ -23,6 +23,8 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse setErrorResponse(response, ErrorStatus.TOKEN_EXPIRED); } else if (Objects.equals(e.getMessage(), "Invalid token")) { setErrorResponse(response, ErrorStatus.INVALID_TOKEN); + } else if (Objects.equals(e.getMessage(), "Token null")) { + setErrorResponse(response, ErrorStatus.TOKEN_NULL); } } catch (IOException e) { throw new RuntimeException(e); diff --git a/src/main/java/com/gamegoo/config/SecurityConfig.java b/src/main/java/com/gamegoo/config/SecurityConfig.java index 9c99f33e..fef13ada 100644 --- a/src/main/java/com/gamegoo/config/SecurityConfig.java +++ b/src/main/java/com/gamegoo/config/SecurityConfig.java @@ -37,7 +37,7 @@ public AuthenticationManager authenticationManager(AuthenticationConfiguration c @Bean public JWTFilter jwtFilter() { - List excludedPaths = Arrays.asList("/api/member/join", "/api/member/login", "/api/member/email"); + List excludedPaths = Arrays.asList("/api/member/join", "/api/member/login", "/api/member/email/*"); return new JWTFilter(jwtUtil, excludedPaths, customUserDetailService); } @@ -55,7 +55,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .httpBasic(AbstractHttpConfigurer::disable) .authorizeHttpRequests((auth) -> auth - .antMatchers("/api/member/join", "/api/member/login", "/api/member/email").permitAll() + .antMatchers("/api/member/join", "/api/member/login", "/api/member/email/*").permitAll() .anyRequest().authenticated()) .addFilterBefore(new JWTExceptionHandlerFilter(), UsernamePasswordAuthenticationFilter.class) .addFilterAt(new LoginFilter(authenticationManager(authenticationConfiguration), jwtUtil), UsernamePasswordAuthenticationFilter.class) diff --git a/src/main/java/com/gamegoo/controller/member/AuthController.java b/src/main/java/com/gamegoo/controller/member/AuthController.java index f868d0ea..fb00add9 100644 --- a/src/main/java/com/gamegoo/controller/member/AuthController.java +++ b/src/main/java/com/gamegoo/controller/member/AuthController.java @@ -30,9 +30,12 @@ public ApiResponse joinMember(@RequestBody JoinDTO joinDTO) { @PostMapping("/email/send") @Operation(summary = "이메일 인증코드 전송 API 입니다.", description = "API for sending email") public ApiResponse sendEmail(@RequestBody EmailDTO emailDTO) { + System.out.println("DD"); String email = emailDTO.getEmail(); - String code = authService.sendEmail(email); - return ApiResponse.onSuccess(code); + System.out.println(email); + + authService.sendEmail(email); + return ApiResponse.onSuccess("인증 이메일을 발송했습니다."); } @PostMapping("/email/verify") @@ -41,6 +44,6 @@ public ApiResponse verifyEmail(@RequestBody EmailCodeDTO emailCodeDTO) { String email = emailCodeDTO.getEmail(); String code = emailCodeDTO.getCode(); authService.verifyEmail(email, code); - return ApiResponse.onSuccess("성공했습니다."); + return ApiResponse.onSuccess("인증코드 검증에 성공했습니다."); } } diff --git a/src/main/java/com/gamegoo/domain/EmailVerifyRecord.java b/src/main/java/com/gamegoo/domain/EmailVerifyRecord.java index 603b4fd3..29e4f5cd 100644 --- a/src/main/java/com/gamegoo/domain/EmailVerifyRecord.java +++ b/src/main/java/com/gamegoo/domain/EmailVerifyRecord.java @@ -23,5 +23,4 @@ public class EmailVerifyRecord extends BaseDateTimeEntity { @Column(name = "code", nullable = false, length = 10) private String code; - } diff --git a/src/main/java/com/gamegoo/filter/JWTFilter.java b/src/main/java/com/gamegoo/filter/JWTFilter.java index 425962d9..54b136e9 100644 --- a/src/main/java/com/gamegoo/filter/JWTFilter.java +++ b/src/main/java/com/gamegoo/filter/JWTFilter.java @@ -1,7 +1,5 @@ package com.gamegoo.filter; -import com.gamegoo.apiPayload.code.status.ErrorStatus; -import com.gamegoo.apiPayload.exception.handler.MemberHandler; import com.gamegoo.security.CustomUserDetails; import com.gamegoo.service.member.CustomUserDetailService; import com.gamegoo.util.JWTUtil; @@ -50,8 +48,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse // Authorization 헤더 검증 if (authorization == null || !authorization.startsWith("Bearer ")) { - System.out.println("token null"); - throw new MemberHandler(ErrorStatus.INVALID_TOKEN); + throw new JwtException("Token null"); } System.out.println("authorization now"); diff --git a/src/main/java/com/gamegoo/service/member/AuthService.java b/src/main/java/com/gamegoo/service/member/AuthService.java index f7f77d98..56018374 100644 --- a/src/main/java/com/gamegoo/service/member/AuthService.java +++ b/src/main/java/com/gamegoo/service/member/AuthService.java @@ -53,7 +53,7 @@ public void joinMember(JoinDTO joinDTO) { } //이메일 인증코드 전송 - public String sendEmail(String email) { + public void sendEmail(String email) { // 중복 확인하기 boolean isPresent = memberRepository.findByEmail(email).isPresent(); if (isPresent) { @@ -73,9 +73,6 @@ public String sendEmail(String email) { .build(); emailVerifyRecordRepository.save(emailVerifyRecord); - - // 인증 번호 반환 - return certificationNumber; } // 이메일 인증코드 검증 diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 6fe7e2c0..daf2e47b 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -7,7 +7,7 @@ spring: password: ${DB_PASSWORD} jpa: hibernate: - ddl-auto: update + ddl-auto: create properties: hibernate: # show_sql: true From 03b76289ef52a0ab1cce7f03f14ad79ffc4a81cc Mon Sep 17 00:00:00 2001 From: Rimi Date: Sat, 29 Jun 2024 20:28:37 +0900 Subject: [PATCH 10/11] =?UTF-8?q?:bug:=20[Fix]=20=ED=98=84=EC=9E=AC?= =?UTF-8?q?=EA=B9=8C=EC=A7=80=20=EA=B0=9C=EB=B0=9C=ED=95=9C=20API=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=99=84=EB=A3=8C=20=EB=B0=8F=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/{ => handler}/CustomUserException.java | 2 +- .../exception/handler/JWTExceptionHandlerFilter.java | 7 +++++-- src/main/java/com/gamegoo/config/SecurityConfig.java | 4 ++-- .../java/com/gamegoo/controller/member/AuthController.java | 3 --- .../com/gamegoo/controller/member/ProfileController.java | 7 ++++++- src/main/java/com/gamegoo/filter/JWTFilter.java | 6 ++---- src/main/java/com/gamegoo/filter/LoginFilter.java | 2 +- .../repository/member/EmailVerifyRecordRepository.java | 5 ++++- src/main/java/com/gamegoo/service/member/AuthService.java | 5 ++++- .../gamegoo/service/member/CustomUserDetailService.java | 6 +++--- src/main/resources/application.yml | 2 +- 11 files changed, 29 insertions(+), 20 deletions(-) rename src/main/java/com/gamegoo/apiPayload/exception/{ => handler}/CustomUserException.java (80%) diff --git a/src/main/java/com/gamegoo/apiPayload/exception/CustomUserException.java b/src/main/java/com/gamegoo/apiPayload/exception/handler/CustomUserException.java similarity index 80% rename from src/main/java/com/gamegoo/apiPayload/exception/CustomUserException.java rename to src/main/java/com/gamegoo/apiPayload/exception/handler/CustomUserException.java index 6e90fa76..fc65bd5d 100644 --- a/src/main/java/com/gamegoo/apiPayload/exception/CustomUserException.java +++ b/src/main/java/com/gamegoo/apiPayload/exception/handler/CustomUserException.java @@ -1,4 +1,4 @@ -package com.gamegoo.apiPayload.exception; +package com.gamegoo.apiPayload.exception.handler; import org.springframework.security.core.AuthenticationException; diff --git a/src/main/java/com/gamegoo/apiPayload/exception/handler/JWTExceptionHandlerFilter.java b/src/main/java/com/gamegoo/apiPayload/exception/handler/JWTExceptionHandlerFilter.java index 220fb0e5..5375185a 100644 --- a/src/main/java/com/gamegoo/apiPayload/exception/handler/JWTExceptionHandlerFilter.java +++ b/src/main/java/com/gamegoo/apiPayload/exception/handler/JWTExceptionHandlerFilter.java @@ -19,12 +19,15 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse try { filterChain.doFilter(request, response); } catch (JwtException e) { + if (Objects.equals(e.getMessage(), "Token expired")) { setErrorResponse(response, ErrorStatus.TOKEN_EXPIRED); - } else if (Objects.equals(e.getMessage(), "Invalid token")) { - setErrorResponse(response, ErrorStatus.INVALID_TOKEN); } else if (Objects.equals(e.getMessage(), "Token null")) { setErrorResponse(response, ErrorStatus.TOKEN_NULL); + } else if (Objects.equals(e.getMessage(), "No Member")) { + setErrorResponse(response, ErrorStatus.MEMBER_NOT_FOUND); + } else { + setErrorResponse(response, ErrorStatus.INVALID_TOKEN); } } catch (IOException e) { throw new RuntimeException(e); diff --git a/src/main/java/com/gamegoo/config/SecurityConfig.java b/src/main/java/com/gamegoo/config/SecurityConfig.java index fef13ada..58581988 100644 --- a/src/main/java/com/gamegoo/config/SecurityConfig.java +++ b/src/main/java/com/gamegoo/config/SecurityConfig.java @@ -37,7 +37,7 @@ public AuthenticationManager authenticationManager(AuthenticationConfiguration c @Bean public JWTFilter jwtFilter() { - List excludedPaths = Arrays.asList("/api/member/join", "/api/member/login", "/api/member/email/*"); + List excludedPaths = Arrays.asList("/api/member/join", "/api/member/login", "/api/member/email"); return new JWTFilter(jwtUtil, excludedPaths, customUserDetailService); } @@ -55,7 +55,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .httpBasic(AbstractHttpConfigurer::disable) .authorizeHttpRequests((auth) -> auth - .antMatchers("/api/member/join", "/api/member/login", "/api/member/email/*").permitAll() + .antMatchers("/api/member/join", "/api/member/login", "/api/member/email/**").permitAll() .anyRequest().authenticated()) .addFilterBefore(new JWTExceptionHandlerFilter(), UsernamePasswordAuthenticationFilter.class) .addFilterAt(new LoginFilter(authenticationManager(authenticationConfiguration), jwtUtil), UsernamePasswordAuthenticationFilter.class) diff --git a/src/main/java/com/gamegoo/controller/member/AuthController.java b/src/main/java/com/gamegoo/controller/member/AuthController.java index fb00add9..c0faf065 100644 --- a/src/main/java/com/gamegoo/controller/member/AuthController.java +++ b/src/main/java/com/gamegoo/controller/member/AuthController.java @@ -30,10 +30,7 @@ public ApiResponse joinMember(@RequestBody JoinDTO joinDTO) { @PostMapping("/email/send") @Operation(summary = "이메일 인증코드 전송 API 입니다.", description = "API for sending email") public ApiResponse sendEmail(@RequestBody EmailDTO emailDTO) { - System.out.println("DD"); String email = emailDTO.getEmail(); - System.out.println(email); - authService.sendEmail(email); return ApiResponse.onSuccess("인증 이메일을 발송했습니다."); } diff --git a/src/main/java/com/gamegoo/controller/member/ProfileController.java b/src/main/java/com/gamegoo/controller/member/ProfileController.java index 37d42b44..30cdaf56 100644 --- a/src/main/java/com/gamegoo/controller/member/ProfileController.java +++ b/src/main/java/com/gamegoo/controller/member/ProfileController.java @@ -10,6 +10,8 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; +import java.util.List; + @RestController @RequiredArgsConstructor @RequestMapping("/api/member") @@ -20,7 +22,10 @@ public class ProfileController { @PutMapping("/gamestyle") @Operation(summary = "gamestyle 추가 및 수정 API 입니다.", description = "API for Gamestyle addition and modification ") public ApiResponse addGameStyle(@RequestBody GameStyleDTO gameStyleDTO) { - profileService.addMemberGameStyles(gameStyleDTO.getGamestyle()); + + List gamestylelist = gameStyleDTO.getGamestyle(); + System.out.println(gamestylelist); + profileService.addMemberGameStyles(gamestylelist); return ApiResponse.onSuccess("게임 스타일 수정이 완료되었습니다."); } diff --git a/src/main/java/com/gamegoo/filter/JWTFilter.java b/src/main/java/com/gamegoo/filter/JWTFilter.java index 54b136e9..fc14689e 100644 --- a/src/main/java/com/gamegoo/filter/JWTFilter.java +++ b/src/main/java/com/gamegoo/filter/JWTFilter.java @@ -51,14 +51,12 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse throw new JwtException("Token null"); } - System.out.println("authorization now"); - + // 인증 시작 // Bearer 부분 제거 후 순수 토큰만 획득 String token = authorization.split(" ")[1]; try { // jwt 토큰에서 id 획득 Long id = jwtUtil.getId(token); - System.out.println(id); // UserDetails에 회원 정보 객체 담기 CustomUserDetails customUserDetails = (CustomUserDetails) customUserDetailService.loadUserById(id); @@ -73,7 +71,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse } catch (ExpiredJwtException e) { throw new JwtException("Token expired"); } catch (JwtException e) { - throw new JwtException("Invalid token"); + throw new JwtException(e.getMessage()); } } diff --git a/src/main/java/com/gamegoo/filter/LoginFilter.java b/src/main/java/com/gamegoo/filter/LoginFilter.java index bbbe7cdb..3e5ab4db 100644 --- a/src/main/java/com/gamegoo/filter/LoginFilter.java +++ b/src/main/java/com/gamegoo/filter/LoginFilter.java @@ -39,7 +39,7 @@ public Authentication attemptAuthentication(HttpServletRequest request, HttpServ // 클라이언트 요청에서 username, password 추출 String email = obtainUsername(request); String password = obtainPassword(request); - + // 스프링 시큐리티에서 username과 password를 검증하기 위해서는 token에 담아야 함 UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(email, password, null); diff --git a/src/main/java/com/gamegoo/repository/member/EmailVerifyRecordRepository.java b/src/main/java/com/gamegoo/repository/member/EmailVerifyRecordRepository.java index 9dba10f3..58845786 100644 --- a/src/main/java/com/gamegoo/repository/member/EmailVerifyRecordRepository.java +++ b/src/main/java/com/gamegoo/repository/member/EmailVerifyRecordRepository.java @@ -1,10 +1,13 @@ package com.gamegoo.repository.member; import com.gamegoo.domain.EmailVerifyRecord; +import org.springframework.data.domain.PageRequest; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import java.util.Optional; public interface EmailVerifyRecordRepository extends JpaRepository { - Optional findByEmailOrderByUpdatedAtDesc(String email); + @Query("SELECT e FROM EmailVerifyRecord e WHERE e.email = :email ORDER BY e.updatedAt DESC") + Optional findByEmailOrderByUpdatedAtDesc(String email, PageRequest pageRequest); } diff --git a/src/main/java/com/gamegoo/service/member/AuthService.java b/src/main/java/com/gamegoo/service/member/AuthService.java index 56018374..2ae9aba4 100644 --- a/src/main/java/com/gamegoo/service/member/AuthService.java +++ b/src/main/java/com/gamegoo/service/member/AuthService.java @@ -10,6 +10,7 @@ import com.gamegoo.repository.member.MemberRepository; import com.gamegoo.util.CodeGeneratorUtil; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.PageRequest; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @@ -78,7 +79,9 @@ public void sendEmail(String email) { // 이메일 인증코드 검증 public void verifyEmail(String email, String code) { // 이메일로 보낸 인증 코드 중 가장 최근의 데이터를 불러옴 - EmailVerifyRecord emailVerifyRecord = emailVerifyRecordRepository.findByEmailOrderByUpdatedAtDesc(email) + EmailVerifyRecord emailVerifyRecord = emailVerifyRecordRepository.findByEmailOrderByUpdatedAtDesc(email, PageRequest.of(0, 1)) + // 가장 최신 기록만 가져오기 + .stream().findFirst() // 해당 이메일이 없을 경우 .orElseThrow(() -> new MemberHandler(ErrorStatus.EMAIL_NOT_FOUND)); diff --git a/src/main/java/com/gamegoo/service/member/CustomUserDetailService.java b/src/main/java/com/gamegoo/service/member/CustomUserDetailService.java index c4f4e40e..bfcad1e0 100644 --- a/src/main/java/com/gamegoo/service/member/CustomUserDetailService.java +++ b/src/main/java/com/gamegoo/service/member/CustomUserDetailService.java @@ -1,6 +1,6 @@ package com.gamegoo.service.member; -import com.gamegoo.apiPayload.exception.CustomUserException; +import com.gamegoo.apiPayload.exception.handler.CustomUserException; import com.gamegoo.domain.Member; import com.gamegoo.repository.member.MemberRepository; import com.gamegoo.security.CustomUserDetails; @@ -26,13 +26,13 @@ public UserDetails loadUserByUsername(String email) { } return new CustomUserDetails(member); }) - .orElseThrow(() -> new JwtException("해당 사용자를 찾을 수 없습니다.")); + .orElseThrow(() -> new JwtException("No Member")); } public UserDetails loadUserById(Long id) throws UsernameNotFoundException { Member member = memberRepository.findById(id) .filter(m -> !m.getBlind()) - .orElseThrow(() -> new JwtException("해당 사용자를 찾을 수 없습니다.")); + .orElseThrow(() -> new JwtException("No Member")); return new CustomUserDetails(member); } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index daf2e47b..6fe7e2c0 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -7,7 +7,7 @@ spring: password: ${DB_PASSWORD} jpa: hibernate: - ddl-auto: create + ddl-auto: update properties: hibernate: # show_sql: true From 0f194a96cabfebb0599baaea81668450955993cb Mon Sep 17 00:00:00 2001 From: Rimi Date: Sat, 29 Jun 2024 22:00:25 +0900 Subject: [PATCH 11/11] =?UTF-8?q?:bug:=20[Fix]=20@GeneratedValue(strategy?= =?UTF-8?q?=20=3D=20GenerationType.IDENTITY)=20AUTO=20->=20IDENTITY=20?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/gamegoo/domain/Block.java | 2 +- src/main/java/com/gamegoo/domain/Board.java | 2 +- src/main/java/com/gamegoo/domain/EmailVerifyRecord.java | 2 +- src/main/java/com/gamegoo/domain/Friend.java | 2 +- src/main/java/com/gamegoo/domain/MatchingRecord.java | 2 +- src/main/java/com/gamegoo/domain/Member.java | 2 +- src/main/java/com/gamegoo/domain/champion/Champion.java | 2 +- src/main/java/com/gamegoo/domain/champion/MemberChampion.java | 2 +- src/main/java/com/gamegoo/domain/chat/Chat.java | 2 +- src/main/java/com/gamegoo/domain/chat/Chatroom.java | 2 +- src/main/java/com/gamegoo/domain/chat/MemberChatroom.java | 2 +- src/main/java/com/gamegoo/domain/gamestyle/GameStyle.java | 2 +- src/main/java/com/gamegoo/domain/gamestyle/MemberGameStyle.java | 2 +- src/main/java/com/gamegoo/domain/manner/MannerKeyword.java | 2 +- src/main/java/com/gamegoo/domain/manner/MannerRating.java | 2 +- .../java/com/gamegoo/domain/manner/MannerRatingKeyword.java | 2 +- src/main/java/com/gamegoo/domain/notification/Notification.java | 2 +- .../java/com/gamegoo/domain/notification/NotificationType.java | 2 +- src/main/java/com/gamegoo/domain/report/Report.java | 2 +- src/main/java/com/gamegoo/domain/report/ReportType.java | 2 +- 20 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/gamegoo/domain/Block.java b/src/main/java/com/gamegoo/domain/Block.java index f2db0ae8..1c5baa2d 100644 --- a/src/main/java/com/gamegoo/domain/Block.java +++ b/src/main/java/com/gamegoo/domain/Block.java @@ -13,7 +13,7 @@ @AllArgsConstructor public class Block extends BaseDateTimeEntity { @Id - @GeneratedValue(strategy = GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "block_id") private Long id; diff --git a/src/main/java/com/gamegoo/domain/Board.java b/src/main/java/com/gamegoo/domain/Board.java index d3bdc923..45ed3965 100644 --- a/src/main/java/com/gamegoo/domain/Board.java +++ b/src/main/java/com/gamegoo/domain/Board.java @@ -15,7 +15,7 @@ public class Board extends BaseDateTimeEntity { @Id - @GeneratedValue(strategy = GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "board_id", nullable = false) private Long id; diff --git a/src/main/java/com/gamegoo/domain/EmailVerifyRecord.java b/src/main/java/com/gamegoo/domain/EmailVerifyRecord.java index 29e4f5cd..ac49a3bb 100644 --- a/src/main/java/com/gamegoo/domain/EmailVerifyRecord.java +++ b/src/main/java/com/gamegoo/domain/EmailVerifyRecord.java @@ -13,7 +13,7 @@ @AllArgsConstructor public class EmailVerifyRecord extends BaseDateTimeEntity { @Id - @GeneratedValue(strategy = GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "record_id") private Long id; diff --git a/src/main/java/com/gamegoo/domain/Friend.java b/src/main/java/com/gamegoo/domain/Friend.java index ccd9bb7c..48f5bfce 100644 --- a/src/main/java/com/gamegoo/domain/Friend.java +++ b/src/main/java/com/gamegoo/domain/Friend.java @@ -12,7 +12,7 @@ @AllArgsConstructor public class Friend extends BaseDateTimeEntity { @Id - @GeneratedValue(strategy = GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "friend_id") private Long id; diff --git a/src/main/java/com/gamegoo/domain/MatchingRecord.java b/src/main/java/com/gamegoo/domain/MatchingRecord.java index caa9dc8a..7f153f48 100644 --- a/src/main/java/com/gamegoo/domain/MatchingRecord.java +++ b/src/main/java/com/gamegoo/domain/MatchingRecord.java @@ -13,7 +13,7 @@ @AllArgsConstructor public class MatchingRecord extends BaseDateTimeEntity { @Id - @GeneratedValue(strategy = GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "matching_id", nullable = false) private Long id; diff --git a/src/main/java/com/gamegoo/domain/Member.java b/src/main/java/com/gamegoo/domain/Member.java index e17a2cfa..3310f6e2 100644 --- a/src/main/java/com/gamegoo/domain/Member.java +++ b/src/main/java/com/gamegoo/domain/Member.java @@ -23,7 +23,7 @@ @AllArgsConstructor public class Member extends BaseDateTimeEntity { @Id - @GeneratedValue(strategy = GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "member_id") private Long id; diff --git a/src/main/java/com/gamegoo/domain/champion/Champion.java b/src/main/java/com/gamegoo/domain/champion/Champion.java index e59a483c..d4c9c5a8 100644 --- a/src/main/java/com/gamegoo/domain/champion/Champion.java +++ b/src/main/java/com/gamegoo/domain/champion/Champion.java @@ -11,7 +11,7 @@ @Setter public class Champion { @Id - @GeneratedValue(strategy = GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "champion_id", nullable = false) private Long id; diff --git a/src/main/java/com/gamegoo/domain/champion/MemberChampion.java b/src/main/java/com/gamegoo/domain/champion/MemberChampion.java index 3623a7d9..d9204f8d 100644 --- a/src/main/java/com/gamegoo/domain/champion/MemberChampion.java +++ b/src/main/java/com/gamegoo/domain/champion/MemberChampion.java @@ -13,7 +13,7 @@ @Table(name = "MemberChampion") public class MemberChampion { @Id - @GeneratedValue(strategy = GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "member_champion_id", nullable = false) private Long id; diff --git a/src/main/java/com/gamegoo/domain/chat/Chat.java b/src/main/java/com/gamegoo/domain/chat/Chat.java index 20a651cc..d6403189 100644 --- a/src/main/java/com/gamegoo/domain/chat/Chat.java +++ b/src/main/java/com/gamegoo/domain/chat/Chat.java @@ -13,7 +13,7 @@ @AllArgsConstructor public class Chat extends BaseDateTimeEntity { @Id - @GeneratedValue(strategy = GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "chat_id") private Long id; diff --git a/src/main/java/com/gamegoo/domain/chat/Chatroom.java b/src/main/java/com/gamegoo/domain/chat/Chatroom.java index b620c530..57592193 100644 --- a/src/main/java/com/gamegoo/domain/chat/Chatroom.java +++ b/src/main/java/com/gamegoo/domain/chat/Chatroom.java @@ -13,7 +13,7 @@ @AllArgsConstructor public class Chatroom extends BaseDateTimeEntity { @Id - @GeneratedValue(strategy = GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "chatroom_id") private Long id; diff --git a/src/main/java/com/gamegoo/domain/chat/MemberChatroom.java b/src/main/java/com/gamegoo/domain/chat/MemberChatroom.java index 8a4e4b07..f0dd20b9 100644 --- a/src/main/java/com/gamegoo/domain/chat/MemberChatroom.java +++ b/src/main/java/com/gamegoo/domain/chat/MemberChatroom.java @@ -15,7 +15,7 @@ @AllArgsConstructor public class MemberChatroom extends BaseDateTimeEntity { @Id - @GeneratedValue(strategy = GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "member_chatroom_id") private Long id; diff --git a/src/main/java/com/gamegoo/domain/gamestyle/GameStyle.java b/src/main/java/com/gamegoo/domain/gamestyle/GameStyle.java index e953f3e7..755df2de 100644 --- a/src/main/java/com/gamegoo/domain/gamestyle/GameStyle.java +++ b/src/main/java/com/gamegoo/domain/gamestyle/GameStyle.java @@ -14,7 +14,7 @@ @AllArgsConstructor public class GameStyle extends BaseDateTimeEntity { @Id - @GeneratedValue(strategy = GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "gamestyle_id", nullable = false) private Long id; diff --git a/src/main/java/com/gamegoo/domain/gamestyle/MemberGameStyle.java b/src/main/java/com/gamegoo/domain/gamestyle/MemberGameStyle.java index f888d2b8..ce97fc1f 100644 --- a/src/main/java/com/gamegoo/domain/gamestyle/MemberGameStyle.java +++ b/src/main/java/com/gamegoo/domain/gamestyle/MemberGameStyle.java @@ -16,7 +16,7 @@ public class MemberGameStyle extends BaseDateTimeEntity { @Id - @GeneratedValue(strategy = GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "member_gamestyle_id", nullable = false) private Long id; diff --git a/src/main/java/com/gamegoo/domain/manner/MannerKeyword.java b/src/main/java/com/gamegoo/domain/manner/MannerKeyword.java index 4fd83025..fa39aa5d 100644 --- a/src/main/java/com/gamegoo/domain/manner/MannerKeyword.java +++ b/src/main/java/com/gamegoo/domain/manner/MannerKeyword.java @@ -12,7 +12,7 @@ @AllArgsConstructor public class MannerKeyword extends BaseDateTimeEntity { @Id - @GeneratedValue(strategy = GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "manner_keyword_id") private Long id; diff --git a/src/main/java/com/gamegoo/domain/manner/MannerRating.java b/src/main/java/com/gamegoo/domain/manner/MannerRating.java index 632bc3e5..9a0453c1 100644 --- a/src/main/java/com/gamegoo/domain/manner/MannerRating.java +++ b/src/main/java/com/gamegoo/domain/manner/MannerRating.java @@ -15,7 +15,7 @@ @AllArgsConstructor public class MannerRating extends BaseDateTimeEntity { @Id - @GeneratedValue(strategy = GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "manner_rating_id") private Long id; diff --git a/src/main/java/com/gamegoo/domain/manner/MannerRatingKeyword.java b/src/main/java/com/gamegoo/domain/manner/MannerRatingKeyword.java index 4d106c21..ff2d9490 100644 --- a/src/main/java/com/gamegoo/domain/manner/MannerRatingKeyword.java +++ b/src/main/java/com/gamegoo/domain/manner/MannerRatingKeyword.java @@ -12,7 +12,7 @@ @AllArgsConstructor public class MannerRatingKeyword extends BaseDateTimeEntity { @Id - @GeneratedValue(strategy = GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "manner_rating_keyword_id", nullable = false) private Long id; diff --git a/src/main/java/com/gamegoo/domain/notification/Notification.java b/src/main/java/com/gamegoo/domain/notification/Notification.java index 5d5c16d7..acaf798d 100644 --- a/src/main/java/com/gamegoo/domain/notification/Notification.java +++ b/src/main/java/com/gamegoo/domain/notification/Notification.java @@ -13,7 +13,7 @@ @AllArgsConstructor public class Notification extends BaseDateTimeEntity { @Id - @GeneratedValue(strategy = GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "notification_id") private Long id; diff --git a/src/main/java/com/gamegoo/domain/notification/NotificationType.java b/src/main/java/com/gamegoo/domain/notification/NotificationType.java index 8016925a..50d8fb00 100644 --- a/src/main/java/com/gamegoo/domain/notification/NotificationType.java +++ b/src/main/java/com/gamegoo/domain/notification/NotificationType.java @@ -12,7 +12,7 @@ @AllArgsConstructor public class NotificationType extends BaseDateTimeEntity { @Id - @GeneratedValue(strategy = GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "notification_type_id") private Long id; diff --git a/src/main/java/com/gamegoo/domain/report/Report.java b/src/main/java/com/gamegoo/domain/report/Report.java index 48cfa6cb..c3f10642 100644 --- a/src/main/java/com/gamegoo/domain/report/Report.java +++ b/src/main/java/com/gamegoo/domain/report/Report.java @@ -14,7 +14,7 @@ @AllArgsConstructor public class Report extends BaseDateTimeEntity { @Id - @GeneratedValue(strategy = GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "report_id") private Long id; diff --git a/src/main/java/com/gamegoo/domain/report/ReportType.java b/src/main/java/com/gamegoo/domain/report/ReportType.java index 18eba6f8..21f9202e 100644 --- a/src/main/java/com/gamegoo/domain/report/ReportType.java +++ b/src/main/java/com/gamegoo/domain/report/ReportType.java @@ -13,7 +13,7 @@ @AllArgsConstructor public class ReportType extends BaseDateTimeEntity { @Id - @GeneratedValue(strategy = GenerationType.AUTO) + @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "report_type_id") private Long id; @Column(name = "report_type_content", nullable = false)