diff --git a/application/src/main/java/org/depromeet/spot/application/common/config/SecurityConfig.java b/application/src/main/java/org/depromeet/spot/application/common/config/SecurityConfig.java index bed6077c..3b6994a2 100644 --- a/application/src/main/java/org/depromeet/spot/application/common/config/SecurityConfig.java +++ b/application/src/main/java/org/depromeet/spot/application/common/config/SecurityConfig.java @@ -33,6 +33,7 @@ public class SecurityConfig { "/api/v1/members/**", "/actuator/**", "/login/oauth2/code/google/**", + "/google/**" }; @Bean diff --git a/application/src/main/java/org/depromeet/spot/application/common/jwt/JwtAuthenticationFilter.java b/application/src/main/java/org/depromeet/spot/application/common/jwt/JwtAuthenticationFilter.java index fa75d8cc..fed63a9e 100644 --- a/application/src/main/java/org/depromeet/spot/application/common/jwt/JwtAuthenticationFilter.java +++ b/application/src/main/java/org/depromeet/spot/application/common/jwt/JwtAuthenticationFilter.java @@ -41,6 +41,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { "/api/v1/levels/info", "/kakao", "/api/v1/jwts", + "/google/callback" }; private static final Map> AUTH_METHOD_WHITELIST = @@ -54,6 +55,10 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { "/api/v1/members/delete", Set.of("DELETE"), "/api/v1/baseball-teams", + Set.of("GET"), + "/api/v2/GOOGLE", + Set.of("GET"), + "/api/v2/KAKAO", Set.of("GET")); @Override @@ -89,6 +94,8 @@ protected void doFilterInternal( } private boolean checkMethodWhitelist(String requestURI, String requestMethod) { + log.info("requestURI: {}", requestURI); + log.info("requestMethod: {}", requestMethod); if (Arrays.stream(AUTH_WHITELIST).anyMatch(requestURI::startsWith)) { return true; } diff --git a/application/src/main/java/org/depromeet/spot/application/member/controller/OauthController.java b/application/src/main/java/org/depromeet/spot/application/member/controller/OauthController.java index c4fca739..e238d349 100644 --- a/application/src/main/java/org/depromeet/spot/application/member/controller/OauthController.java +++ b/application/src/main/java/org/depromeet/spot/application/member/controller/OauthController.java @@ -44,29 +44,29 @@ public JwtTokenResponse create(@RequestBody @Valid RegisterV2Req request) { return new JwtTokenResponse(jwtTokenUtil.getJWTToken(memberResult)); } - @GetMapping("/api/v2/members/{snsProvider}/{token}") + @GetMapping("/api/v2/members/{snsProvider}") @ResponseStatus(HttpStatus.OK) @Operation(summary = "Member 로그인 API") public JwtTokenResponse login( @PathVariable("snsProvider") @Parameter(name = "snsProvider", description = "KAKAO/GOOGLE", required = true) SnsProvider snsProvider, - @PathVariable("token") + @RequestParam @Parameter( - name = "token", - description = "sns 카카오는 accessToken, 구글은 authToken", + name = "accessToken", + description = "sns 카카오는 accessToken", required = true) - String token) { + String accessToken) { - Member member = oauthUsecase.login(snsProvider, token); + Member member = oauthUsecase.login(snsProvider, accessToken); return new JwtTokenResponse(jwtTokenUtil.getJWTToken(member)); } // TODO : /api/v2/members를 RequestMapping으로 빼면 구글 로그인에서 4xx Exception 발생 @GetMapping("/api/v2/members/authorization/{snsProvider}") @ResponseStatus(HttpStatus.OK) - @Operation(summary = "(백엔드용)accessToken을 받아오기 위한 API") - public String getAccessToken2( + @Operation(summary = "accessToken을 받아오기 위한 API") + public String getAccessToken( @PathVariable("snsProvider") SnsProvider snsProvider, @RequestParam String code) { String token = oauthUsecase.getOauthAccessToken(snsProvider, code); log.info("snsProvider : {}", snsProvider); diff --git a/common/src/main/java/org/depromeet/spot/common/exception/member/MemberErrorCode.java b/common/src/main/java/org/depromeet/spot/common/exception/member/MemberErrorCode.java index cc815f43..47d8e2d4 100644 --- a/common/src/main/java/org/depromeet/spot/common/exception/member/MemberErrorCode.java +++ b/common/src/main/java/org/depromeet/spot/common/exception/member/MemberErrorCode.java @@ -11,6 +11,7 @@ public enum MemberErrorCode implements ErrorCode { MEMBER_NICKNAME_CONFLICT(HttpStatus.CONFLICT, "M002", "닉네임이 중복됩니다."), INVALID_LEVEL(HttpStatus.INTERNAL_SERVER_ERROR, "M003", "잘못된 레벨입니다."), INACTIVE_MEMBER(HttpStatus.GONE, "M004", "탈퇴한 유저입니다."), + MEMBER_CONFLICT(HttpStatus.BAD_REQUEST, "M005", "이미 가입된 유저입니다."), ; private final HttpStatus status; diff --git a/common/src/main/java/org/depromeet/spot/common/exception/member/MemberException.java b/common/src/main/java/org/depromeet/spot/common/exception/member/MemberException.java index 43f3eee6..eb3c2550 100644 --- a/common/src/main/java/org/depromeet/spot/common/exception/member/MemberException.java +++ b/common/src/main/java/org/depromeet/spot/common/exception/member/MemberException.java @@ -36,4 +36,11 @@ public InactiveMemberException() { super(MemberErrorCode.INACTIVE_MEMBER); } } + + public static class MemberConflictException extends MemberException { + + public MemberConflictException() { + super(MemberErrorCode.MEMBER_CONFLICT); + } + } } diff --git a/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/member/entity/MemberEntity.java b/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/member/entity/MemberEntity.java index 0849e47f..c97e31a1 100644 --- a/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/member/entity/MemberEntity.java +++ b/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/member/entity/MemberEntity.java @@ -25,7 +25,7 @@ public class MemberEntity extends BaseEntity { // TODO : email 받아온 후 nullable = false로 바꿔야함. - @Column(name = "email", unique = true, length = 50) + @Column(name = "email", length = 50) private String email; // TODO : 이름 받아온 후 nullable = false로 바꿔야함. @@ -36,7 +36,7 @@ public class MemberEntity extends BaseEntity { private String nickname; // TODO : phone_number 받아온 후 nullable = false로 바꿔야함. - @Column(name = "phone_number", unique = true, length = 13) + @Column(name = "phone_number", length = 13) private String phoneNumber; @ManyToOne(fetch = FetchType.LAZY) @@ -52,7 +52,7 @@ public class MemberEntity extends BaseEntity { @Column(name = "sns_provider", nullable = false, length = 20) private String snsProvider; - @Column(name = "id_token", nullable = false, unique = true, length = 255) + @Column(name = "id_token", nullable = false, length = 255) private String idToken; @Column(name = "team_id", length = 10) diff --git a/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/member/repository/MemberJpaRepository.java b/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/member/repository/MemberJpaRepository.java index ecc0310f..f644722e 100644 --- a/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/member/repository/MemberJpaRepository.java +++ b/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/member/repository/MemberJpaRepository.java @@ -10,7 +10,8 @@ import org.springframework.data.repository.query.Param; public interface MemberJpaRepository extends JpaRepository { - Optional findByIdToken(String idToken); + @Query("select m from MemberEntity m where m.idToken = :idToken and m.deletedAt is null") + Optional findByIdToken(@Param("idToken") String idToken); @Query("select m from MemberEntity m " + "join fetch m.level l " + "where m.id = :id") Optional findByIdWithLevel(@Param("id") Long id); diff --git a/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/member/repository/MemberRepositoryImpl.java b/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/member/repository/MemberRepositoryImpl.java index c2165f65..16035eb7 100644 --- a/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/member/repository/MemberRepositoryImpl.java +++ b/infrastructure/src/main/java/org/depromeet/spot/infrastructure/jpa/member/repository/MemberRepositoryImpl.java @@ -1,6 +1,7 @@ package org.depromeet.spot.infrastructure.jpa.member.repository; import java.time.LocalDateTime; +import java.util.Optional; import org.depromeet.spot.common.exception.member.MemberException.MemberNotFoundException; import org.depromeet.spot.domain.member.Level; @@ -37,11 +38,8 @@ public Member updateLevel(Member member) { } @Override - public Member findByIdToken(String idToken) { - return memberJpaRepository - .findByIdToken(idToken) - .map(MemberEntity::toDomain) - .orElseThrow(MemberNotFoundException::new); + public Optional findByIdToken(String idToken) { + return memberJpaRepository.findByIdToken(idToken).map(MemberEntity::toDomain); } @Override diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/port/out/member/MemberRepository.java b/usecase/src/main/java/org/depromeet/spot/usecase/port/out/member/MemberRepository.java index b4ff5962..deb1044d 100644 --- a/usecase/src/main/java/org/depromeet/spot/usecase/port/out/member/MemberRepository.java +++ b/usecase/src/main/java/org/depromeet/spot/usecase/port/out/member/MemberRepository.java @@ -1,6 +1,7 @@ package org.depromeet.spot.usecase.port.out.member; import java.time.LocalDateTime; +import java.util.Optional; import org.depromeet.spot.domain.member.Level; import org.depromeet.spot.domain.member.Member; @@ -13,7 +14,7 @@ public interface MemberRepository { Member updateLevel(Member member); - Member findByIdToken(String idToken); + Optional findByIdToken(String idToken); boolean existsByNickname(String nickname); diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/service/member/MemberService.java b/usecase/src/main/java/org/depromeet/spot/usecase/service/member/MemberService.java index e2c5ec3c..92804f1a 100644 --- a/usecase/src/main/java/org/depromeet/spot/usecase/service/member/MemberService.java +++ b/usecase/src/main/java/org/depromeet/spot/usecase/service/member/MemberService.java @@ -1,9 +1,12 @@ package org.depromeet.spot.usecase.service.member; import java.time.LocalDateTime; +import java.util.Optional; import org.depromeet.spot.common.exception.member.MemberException.InactiveMemberException; +import org.depromeet.spot.common.exception.member.MemberException.MemberConflictException; import org.depromeet.spot.common.exception.member.MemberException.MemberNicknameConflictException; +import org.depromeet.spot.common.exception.member.MemberException.MemberNotFoundException; import org.depromeet.spot.domain.member.Level; import org.depromeet.spot.domain.member.Member; import org.depromeet.spot.domain.team.BaseballTeam; @@ -39,14 +42,23 @@ public Member create(String accessToken, Member member) { } Member memberResult = oauthRepository.getKakaoRegisterUserInfo(accessToken, member); Level initialLevel = readLevelUsecase.findInitialLevel(); - // 이미 있는 유저를 검증할 필요 없음 -> 최초 시도가 로그인먼저 들어오기 때문. + + // 이미 가입된 유저 Exception + Optional existedMember = memberRepository.findByIdToken(memberResult.getIdToken()); + if (existedMember.isPresent()) { + throw new MemberConflictException(); + } + return memberRepository.save(memberResult, initialLevel); } @Override public Member login(String accessToken) { Member memberResult = oauthRepository.getLoginUserInfo(accessToken); - Member existedMember = memberRepository.findByIdToken(memberResult.getIdToken()); + Member existedMember = + memberRepository + .findByIdToken(memberResult.getIdToken()) + .orElseThrow(MemberNotFoundException::new); // 회원 탈퇴 유저일 경우 재가입 if (existedMember.getDeletedAt() != null) { @@ -71,7 +83,9 @@ public String getAccessToken(String idCode) { @Override public boolean deleteMember(String accessToken) { Member memberResult = oauthRepository.getLoginUserInfo(accessToken); - memberRepository.findByIdToken(memberResult.getIdToken()); + memberRepository + .findByIdToken(memberResult.getIdToken()) + .orElseThrow(MemberNotFoundException::new); memberRepository.deleteByIdToken(memberResult.getIdToken()); return true; diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/service/oauth/OauthService.java b/usecase/src/main/java/org/depromeet/spot/usecase/service/oauth/OauthService.java index 3a18126e..28dc5a93 100644 --- a/usecase/src/main/java/org/depromeet/spot/usecase/service/oauth/OauthService.java +++ b/usecase/src/main/java/org/depromeet/spot/usecase/service/oauth/OauthService.java @@ -1,7 +1,11 @@ package org.depromeet.spot.usecase.service.oauth; +import java.util.Optional; + import org.depromeet.spot.common.exception.member.MemberException.InactiveMemberException; +import org.depromeet.spot.common.exception.member.MemberException.MemberConflictException; import org.depromeet.spot.common.exception.member.MemberException.MemberNicknameConflictException; +import org.depromeet.spot.common.exception.member.MemberException.MemberNotFoundException; import org.depromeet.spot.domain.member.Level; import org.depromeet.spot.domain.member.Member; import org.depromeet.spot.domain.member.enums.SnsProvider; @@ -31,22 +35,23 @@ public Member create(String accessToken, Member member) { Member memberResult = oauthRepository.getOauthRegisterUserInfo(accessToken, member); Level initialLevel = readLevelUsecase.findInitialLevel(); - return memberRepository.save(memberResult, initialLevel); + // 이미 가입된 유저일 경우 Exception + Optional existedMember = memberRepository.findByIdToken(memberResult.getIdToken()); + if (existedMember.isPresent()) { + throw new MemberConflictException(); + } + + return existedMember.orElseGet(() -> memberRepository.save(memberResult, initialLevel)); } @Override - public Member login(SnsProvider snsProvider, String token) { - String accessToken; - switch (snsProvider) { - case KAKAO: - accessToken = token; - break; - default: - accessToken = oauthRepository.getOauthAccessToken(snsProvider, token); - break; - } + public Member login(SnsProvider snsProvider, String accessToken) { + Member memberResult = oauthRepository.getOauthLoginUserInfo(snsProvider, accessToken); - Member existedMember = memberRepository.findByIdToken(memberResult.getIdToken()); + Member existedMember = + memberRepository + .findByIdToken(memberResult.getIdToken()) + .orElseThrow(MemberNotFoundException::new); // 회원 탈퇴 유저일 경우 재가입 if (existedMember.getDeletedAt() != null) {