Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Member 도메인에 클린 아키텍처 적용 #581

Open
wants to merge 4 commits into
base: chongdae
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.zzang.chongdae.auth.config;

import com.zzang.chongdae.auth.controller.CookieConsumer;
import com.zzang.chongdae.auth.service.AuthService;
import com.zzang.chongdae.auth.service.JwtTokenProvider;
import com.zzang.chongdae.member.repository.MemberRepository;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
Expand All @@ -14,13 +14,13 @@
@Configuration
public class AuthWebMvcConfig implements WebMvcConfigurer {

private final AuthService authService;
private final CookieConsumer cookieConsumer;
private final JwtTokenProvider jwtTokenProvider;
private final MemberRepository memberRepository;

@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new MemberArgumentResolver(authService, cookieConsumer));
resolvers.add(new MemberArgumentResolver(cookieConsumer, jwtTokenProvider, memberRepository));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.zzang.chongdae.auth.config;

import com.zzang.chongdae.auth.controller.CookieConsumer;
import com.zzang.chongdae.auth.service.AuthService;
import com.zzang.chongdae.auth.service.JwtTokenProvider;
import com.zzang.chongdae.global.exception.MarketException;
import com.zzang.chongdae.member.exception.MemberErrorCode;
import com.zzang.chongdae.member.repository.MemberRepository;
import com.zzang.chongdae.member.repository.entity.MemberEntity;
import jakarta.servlet.http.HttpServletRequest;
import lombok.AllArgsConstructor;
Expand All @@ -14,8 +17,9 @@
@AllArgsConstructor
public class MemberArgumentResolver implements HandlerMethodArgumentResolver {

private final AuthService authService;
private final CookieConsumer cookieConsumer;
private final JwtTokenProvider jwtTokenProvider;
private final MemberRepository memberRepository;

@Override
public boolean supportsParameter(MethodParameter parameter) {
Expand All @@ -29,6 +33,8 @@ public MemberEntity resolveArgument(MethodParameter parameter,
WebDataBinderFactory binderFactory) {
HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
String token = cookieConsumer.getAccessToken(request.getCookies());
return authService.findMemberByAccessToken(token);
Long memberId = jwtTokenProvider.getMemberIdByAccessToken(token);
return memberRepository.findById(memberId)
.orElseThrow(() -> new MarketException(MemberErrorCode.NOT_FOUND));
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.zzang.chongdae.auth.controller;

import com.zzang.chongdae.auth.domain.AuthToken;
import com.zzang.chongdae.auth.service.AuthService;
import com.zzang.chongdae.auth.service.dto.AuthInfoDto;
import com.zzang.chongdae.auth.service.dto.AuthTokenDto;
import com.zzang.chongdae.auth.service.dto.KakaoLoginRequest;
import com.zzang.chongdae.auth.service.dto.LoginResponse;
import com.zzang.chongdae.logging.config.LoggingMasked;
Expand Down Expand Up @@ -31,20 +31,20 @@ public ResponseEntity<LoginResponse> kakaoLogin(
@RequestBody @Valid KakaoLoginRequest request, HttpServletResponse servletResponse) {
AuthInfoDto authInfo = authService.kakaoLogin(request);
addTokenToHttpServletResponse(authInfo.authToken(), servletResponse);
LoginResponse response = new LoginResponse(authInfo.authMember());
LoginResponse response = new LoginResponse(authInfo.loginMember());
return ResponseEntity.ok(response);
}

@PostMapping("/auth/refresh")
public ResponseEntity<Void> refresh(
HttpServletRequest servletRequest, HttpServletResponse servletResponse) {
String refreshToken = cookieConsumer.getRefreshToken(servletRequest.getCookies());
AuthTokenDto authToken = authService.refresh(refreshToken);
AuthToken authToken = authService.refresh(refreshToken);
addTokenToHttpServletResponse(authToken, servletResponse);
return ResponseEntity.ok().build();
}

private void addTokenToHttpServletResponse(AuthTokenDto authToken, HttpServletResponse servletResponse) {
private void addTokenToHttpServletResponse(AuthToken authToken, HttpServletResponse servletResponse) {
List<Cookie> cookies = cookieExtractor.extractAuthCookies(authToken);
cookieConsumer.addCookies(servletResponse, cookies);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.zzang.chongdae.auth.controller;

import com.zzang.chongdae.auth.service.dto.AuthTokenDto;
import com.zzang.chongdae.auth.domain.AuthToken;
import jakarta.servlet.http.Cookie;
import java.util.ArrayList;
import java.util.List;
Expand All @@ -12,7 +12,7 @@ public class CookieProducer {
private static final String ACCESS_TOKEN_COOKIE_NAME = "access_token";
private static final String REFRESH_TOKEN_COOKIE_NAME = "refresh_token";

public List<Cookie> extractAuthCookies(AuthTokenDto authToken) {
public List<Cookie> extractAuthCookies(AuthToken authToken) {
List<Cookie> cookies = new ArrayList<>();
cookies.add(createCookie(ACCESS_TOKEN_COOKIE_NAME, authToken.accessToken()));
cookies.add(createCookie(REFRESH_TOKEN_COOKIE_NAME, authToken.refreshToken()));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.zzang.chongdae.auth.domain;

public record AuthToken(String accessToken, String refreshToken) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.zzang.chongdae.auth.domain;

import com.zzang.chongdae.member.domain.AuthProvider;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class KakaoMember {

private final AuthProvider provider = AuthProvider.KAKAO;
private final String loginId;

public KakaoMember(Long kakaoId) {
this.loginId = AuthProvider.KAKAO.buildLoginId(kakaoId.toString());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.zzang.chongdae.auth.domain;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class LoginMember {

private final Long id;
private final String nickname;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.zzang.chongdae.auth.domain;

import com.zzang.chongdae.member.domain.AuthProvider;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class SignupMember {

private final String nickname;
private final AuthProvider provider;
private final String loginId;
private final String password;

public SignupMember(String nickname, String password, KakaoMember info) {
this(nickname, info.getProvider(), info.getLoginId(), password);
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.zzang.chongdae.auth.service;

import com.zzang.chongdae.auth.domain.KakaoMember;
import com.zzang.chongdae.auth.exception.KakaoLoginExceptionHandler;
import com.zzang.chongdae.auth.service.dto.KakaoLoginResponseDto;
import com.zzang.chongdae.member.domain.AuthProvider;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpHeaders;
import org.springframework.web.client.RestClient;
Expand All @@ -11,18 +11,18 @@
public class AuthClient {

private static final String BEARER_HEADER_FORMAT = "Bearer %s";
private static final String GET_KAKAO_USER_INFO_URI = "https://kapi.kakao.com/v2/user/me";
private static final String GET_KAKAO_MEMBER_INFO_URI = "https://kapi.kakao.com/v2/user/me";

private final RestClient restClient;

public String getKakaoUserInfo(String accessToken) {
KakaoLoginResponseDto responseDto = restClient.get()
.uri(GET_KAKAO_USER_INFO_URI)
public KakaoMember getKakaoMember(String accessToken) {
KakaoLoginResponseDto response = restClient.get()
.uri(GET_KAKAO_MEMBER_INFO_URI)
.header(HttpHeaders.AUTHORIZATION, createAuthorization(accessToken))
.retrieve()
.onStatus(new KakaoLoginExceptionHandler())
.body(KakaoLoginResponseDto.class);
return AuthProvider.KAKAO.buildLoginId(responseDto.id().toString()); // TODO: NPE 처리 고려하기
return new KakaoMember(response.id()); // TODO: NPE 처리 고려하기
}

private String createAuthorization(String accessToken) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
package com.zzang.chongdae.auth.service;

import com.zzang.chongdae.auth.domain.AuthToken;
import com.zzang.chongdae.auth.domain.KakaoMember;
import com.zzang.chongdae.auth.domain.LoginMember;
import com.zzang.chongdae.auth.domain.SignupMember;
import com.zzang.chongdae.auth.service.dto.AuthInfoDto;
import com.zzang.chongdae.auth.service.dto.AuthMemberDto;
import com.zzang.chongdae.auth.service.dto.AuthTokenDto;
import com.zzang.chongdae.auth.service.dto.KakaoLoginRequest;
import com.zzang.chongdae.global.config.WriterDatabase;
import com.zzang.chongdae.global.exception.MarketException;
import com.zzang.chongdae.member.domain.AuthProvider;
import com.zzang.chongdae.member.exception.MemberErrorCode;
import com.zzang.chongdae.member.repository.MemberRepository;
import com.zzang.chongdae.member.repository.entity.MemberEntity;
import com.zzang.chongdae.member.service.MemberStorage;
import com.zzang.chongdae.member.service.NicknameGenerator;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
Expand All @@ -19,41 +17,34 @@
@Service
public class AuthService {

private final MemberRepository memberRepository;
private final MemberStorage memberStorage;
private final PasswordEncoder passwordEncoder;
private final JwtTokenProvider jwtTokenProvider;
private final NicknameGenerator nickNameGenerator;
private final AuthClient authClient;

@WriterDatabase
public AuthInfoDto kakaoLogin(KakaoLoginRequest request) {
String loginId = authClient.getKakaoUserInfo(request.accessToken());
AuthProvider provider = AuthProvider.KAKAO;
MemberEntity member = memberRepository.findByLoginId(loginId)
.orElseGet(() -> signup(provider, loginId));
return login(member);
public AuthInfoDto kakaoLogin(KakaoLoginRequest request) { // TODO: LoginResponseDTO로 이름 변경하기
KakaoMember kakaoMember = authClient.getKakaoMember(request.accessToken());
LoginMember loginMember = memberStorage.findByLoginId(kakaoMember.getLoginId())
.orElseGet(() -> signup(kakaoMember));
return login(loginMember);
}

private MemberEntity signup(AuthProvider provider, String loginId) {
private LoginMember signup(KakaoMember kakaoMember) {
String nickname = nickNameGenerator.generate();
String password = passwordEncoder.encode(UUID.randomUUID().toString());
MemberEntity member = new MemberEntity(nickNameGenerator.generate(), provider, loginId, password);
return memberRepository.save(member);
SignupMember signupMember = new SignupMember(nickname, password, kakaoMember);
return memberStorage.save(signupMember);
}

private AuthInfoDto login(MemberEntity member) {
AuthMemberDto authMember = new AuthMemberDto(member);
AuthTokenDto authToken = jwtTokenProvider.createAuthToken(member.getId().toString());
return new AuthInfoDto(authMember, authToken);
private AuthInfoDto login(LoginMember loginMember) {
AuthToken authToken = jwtTokenProvider.createAuthToken(loginMember.getId().toString());
return new AuthInfoDto(loginMember, authToken);
}

public AuthTokenDto refresh(String refreshToken) {
public AuthToken refresh(String refreshToken) {
Long memberId = jwtTokenProvider.getMemberIdByRefreshToken(refreshToken);
return jwtTokenProvider.createAuthToken(memberId.toString());
}

public MemberEntity findMemberByAccessToken(String token) {
Long memberId = jwtTokenProvider.getMemberIdByAccessToken(token);
return memberRepository.findById(memberId)
.orElseThrow(() -> new MarketException(MemberErrorCode.NOT_FOUND));
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.zzang.chongdae.auth.service;

import com.zzang.chongdae.auth.domain.AuthToken;
import com.zzang.chongdae.auth.exception.AuthErrorCode;
import com.zzang.chongdae.auth.service.dto.AuthTokenDto;
import com.zzang.chongdae.global.exception.MarketException;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
Expand Down Expand Up @@ -36,8 +36,8 @@ public JwtTokenProvider(@Value("${security.jwt.token.access-secret-key}") String
this.clock = clock;
}

public AuthTokenDto createAuthToken(String payload) {
return new AuthTokenDto(createToken(payload, accessSecretKey, accessTokenExpired),
public AuthToken createAuthToken(String payload) {
return new AuthToken(createToken(payload, accessSecretKey, accessTokenExpired),
createToken(payload, refreshSecretKey, refreshTokenExpired));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
package com.zzang.chongdae.auth.service.dto;

public record AuthInfoDto(AuthMemberDto authMember, AuthTokenDto authToken) {
import com.zzang.chongdae.auth.domain.AuthToken;
import com.zzang.chongdae.auth.domain.LoginMember;

public record AuthInfoDto(LoginMember loginMember, AuthToken authToken) {
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.zzang.chongdae.auth.service.dto;

import com.zzang.chongdae.auth.domain.LoginMember;

public record LoginResponse(Long memberId, String nickname) {

public LoginResponse(AuthMemberDto authMember) {
this(authMember.id(), authMember.nickname());
public LoginResponse(LoginMember loginMember) {
this(loginMember.getId(), loginMember.getNickname());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.zzang.chongdae.member.repository;

import com.zzang.chongdae.auth.domain.LoginMember;
import com.zzang.chongdae.auth.domain.SignupMember;
import com.zzang.chongdae.member.repository.entity.MemberEntity;
import com.zzang.chongdae.member.service.MemberStorage;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

@RequiredArgsConstructor
@Component
public class MemberPersistenceAdaptor implements MemberStorage {

private final MemberRepository memberRepository;

@Override
public Optional<LoginMember> findByLoginId(String loginId) {
Optional<MemberEntity> member = memberRepository.findByLoginId(loginId);
return member.map(MemberEntity::toLoginMember);
}

@Override
public LoginMember save(SignupMember signupMember) {
MemberEntity member = new MemberEntity(signupMember);
MemberEntity savedMember = memberRepository.save(member);
return savedMember.toLoginMember();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@

public interface MemberRepository extends JpaRepository<MemberEntity, Long> {

Optional<MemberEntity> findByPassword(String password);

boolean existsByPassword(String password);

boolean existsByNickname(String nickname);

Optional<MemberEntity> findByLoginId(String loginId);
Expand Down
Loading
Loading