Skip to content

Commit

Permalink
Merge branch 'main' into feat/BSVR-249
Browse files Browse the repository at this point in the history
  • Loading branch information
pminsung12 authored Aug 29, 2024
2 parents 371eeab + 94033c0 commit c7170ea
Show file tree
Hide file tree
Showing 16 changed files with 85 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public class SecurityConfig {
"/api/v1/members/**",
"/actuator/**",
"/login/oauth2/code/google/**",
"/google/**"
};

@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
"/api/v1/levels/info",
"/kakao",
"/api/v1/jwts",
"/google/callback"
};

private static final Map<String, Set<String>> AUTH_METHOD_WHITELIST =
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,11 @@ public InactiveMemberException() {
super(MemberErrorCode.INACTIVE_MEMBER);
}
}

public static class MemberConflictException extends MemberException {

public MemberConflictException() {
super(MemberErrorCode.MEMBER_CONFLICT);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "aws.s3")
public record ObjectStorageProperties(String accessKey, String secretKey, String bucketName) {}
public record ObjectStorageProperties(
String accessKey, String secretKey, String bucketName, String basicProfileImageUrl) {}
Original file line number Diff line number Diff line change
Expand Up @@ -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로 바꿔야함.
Expand All @@ -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)
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
import org.springframework.data.repository.query.Param;

public interface MemberJpaRepository extends JpaRepository<MemberEntity, Long> {
Optional<MemberEntity> findByIdToken(String idToken);
@Query("select m from MemberEntity m where m.idToken = :idToken and m.deletedAt is null")
Optional<MemberEntity> findByIdToken(@Param("idToken") String idToken);

@Query("select m from MemberEntity m " + "join fetch m.level l " + "where m.id = :id")
Optional<MemberEntity> findByIdWithLevel(@Param("id") Long id);
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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<Member> findByIdToken(String idToken) {
return memberJpaRepository.findByIdToken(idToken).map(MemberEntity::toDomain);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import org.depromeet.spot.common.exception.oauth.OauthException.InvalidAcessTokenException;
import org.depromeet.spot.domain.member.Member;
import org.depromeet.spot.domain.member.enums.SnsProvider;
import org.depromeet.spot.infrastructure.aws.property.ObjectStorageProperties;
import org.depromeet.spot.infrastructure.jpa.oauth.config.OauthProperties;
import org.depromeet.spot.infrastructure.jpa.oauth.entity.GoogleTokenEntity;
import org.depromeet.spot.infrastructure.jpa.oauth.entity.GoogleUserInfoEntity;
Expand All @@ -28,6 +29,8 @@ public class OauthRepositoryImpl implements OauthRepository {
private final String BEARER = "Bearer";
private final OauthProperties properties;

private final ObjectStorageProperties objectStorageProperties;

private final String AUTHORIZATION_CODE = "authorization_code";

@Override
Expand Down Expand Up @@ -136,18 +139,21 @@ public String getOauthAccessToken(SnsProvider snsProvider, String authorizationC
@Override
public Member getKakaoRegisterUserInfo(String accessToken, Member member) {
KakaoUserInfoEntity userInfo = getKakaoUserInfo(accessToken);
log.info("basicProfileImage : {}", objectStorageProperties.basicProfileImageUrl());

// 회원가입 시 받은 정보를 바탕으로 member로 변환해서 리턴.
return userInfo.toKakaoDomain(member);
return userInfo.toKakaoDomain(member, objectStorageProperties.basicProfileImageUrl());
}

@Override
public Member getOauthRegisterUserInfo(String accessToken, Member member) {
switch (member.getSnsProvider()) {
case KAKAO:
return getKakaoUserInfo(accessToken).toKakaoDomain(member);
return getKakaoUserInfo(accessToken)
.toKakaoDomain(member, objectStorageProperties.basicProfileImageUrl());
default:
return getGoogleUserInfo(accessToken).toGoogleDomain(member);
return getGoogleUserInfo(accessToken)
.toGoogleDomain(member, objectStorageProperties.basicProfileImageUrl());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ public class GoogleUserInfoEntity extends BaseEntity {
@JsonProperty("picture")
public String profileImageUrl;

public Member toGoogleDomain(Member member) {
public Member toGoogleDomain(Member member, String basicProfileImageUrl) {
return Member.builder()
.email(email)
.nickname(member.getNickname())
.profileImage(profileImageUrl)
.profileImage(basicProfileImageUrl)
.snsProvider(SnsProvider.GOOGLE)
.idToken(idToken)
.role(MemberRole.ROLE_USER)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Getter
@NoArgsConstructor // 역직렬화를 위한 기본 생성자
@JsonIgnoreProperties(ignoreUnknown = true)
Expand Down Expand Up @@ -94,13 +96,13 @@ public class Profile {
}
}

public Member toKakaoDomain(Member member) {
public Member toKakaoDomain(Member member, String basicProfileImageUrl) {
return Member.builder()
.email(kakaoAccount.email)
.name(kakaoAccount.name)
.nickname(member.getNickname())
.phoneNumber(kakaoAccount.phoneNumber)
.profileImage(kakaoAccount.profile.profileImageUrl)
.profileImage(basicProfileImageUrl)
.snsProvider(SnsProvider.KAKAO)
.idToken(getId().toString())
.role(MemberRole.ROLE_USER)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ class PresignedUrlGeneratorTest {
@BeforeEach
void init() {
ObjectStorageProperties objectStorageProperties =
new ObjectStorageProperties("accessKey", "secretKey", "bucketName");
new ObjectStorageProperties(
"accessKey", "secretKey", "bucketName", "basicProfileImageUrl");
FakeAmazonS3Config amazonS3 = new FakeAmazonS3Config(objectStorageProperties);

FakeTimeUsecase fakeTimeUsecase = new FakeTimeUsecase("2024-07-09 21:00:00");
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -13,7 +14,7 @@ public interface MemberRepository {

Member updateLevel(Member member);

Member findByIdToken(String idToken);
Optional<Member> findByIdToken(String idToken);

boolean existsByNickname(String nickname);

Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -39,14 +42,23 @@ public Member create(String accessToken, Member member) {
}
Member memberResult = oauthRepository.getKakaoRegisterUserInfo(accessToken, member);
Level initialLevel = readLevelUsecase.findInitialLevel();
// 이미 있는 유저를 검증할 필요 없음 -> 최초 시도가 로그인먼저 들어오기 때문.

// 이미 가입된 유저 Exception
Optional<Member> 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) {
Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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<Member> 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) {
Expand Down

0 comments on commit c7170ea

Please sign in to comment.