이번 포스팅에서는 User와 Auth 부분을 구현할 예정이다.
그렇지만 User는 매우 간단하다.
지난 포스팅에서 얘기 했듯이 회원을 등록하는게 User-Service가 하는 일이다.
다만 1가지 추가가 되었는데 Auth에서 해당 User를 찾을 수 있도록,
Email을 통한 Read 작업이라고 할 수 있다.
회원 가입은 매우 간단하다.
@Transactional
public void signup(SignupRequestDto requestDto) {
String encodedPassword = passwordEncoder.encode(requestDto.getPassword());
// 저장하기 전 User 객체 생성
User newUser = User.builder()
.username(requestDto.getUsername())
.email(requestDto.getEmail())
.password(encodedPassword)
.phoneNumber(requestDto.getPhoneNumber())
.role(UserRole.USER)
.build();
// User가 이미 존재하는지 확인
if(userRepository.findByEmail(newUser.getEmail()).isEmpty()) {
userRepository.save(newUser);
} else {
throw new CustomException(ErrorCode.CONFLICT_USER);
}
}
단순하게 Dto에 담긴 내용을 꺼내 이미 newUser로 객체 생성한 뒤
조건을 통해 isEmpty를 만족한다면 기존에 존재하지 않은 email로 인식하여 가입에 성공하고,
그 외의 경우는 중복 처리를 해준다.
회원 조회 역시 간단하다.
@Transactional(readOnly = true)
public UserDto findEmail(String email) {
User user = userRepository.findByEmail(email)
.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));
return UserDto.builder()
.id(user.getId())
.username(user.getUsername())
.email(user.getEmail())
.phoneNumber(user.getPhoneNumber())
.role(user.getRole().toString())
.build();
}
딱히 설명할 게 없으므로 Pass하도록 하겠다.
일단 서비스 로직을 작성하기 전에 잠깐 얘기하자면
User와 Auth를 분리하기로 했다.
가능하면 지금부터 분리할 수 있는 내용은 분리하는게 조금 더 낫다는 판단이 있었기 때문이다.
일단 Auth 서비스는 현재 시점 기준으로 db를 따로 갖고있지 않는다.
아마 OAuth나 그 외의 서드파티 로그인을 구현한다 해도 DB를 가지고 있지 않을 예정이다.
User 서비스의 어떤 방식으로 가입했는지 구분할 수 있는 컬럼이 생기는 변화가 존재할 예정이다.
따라서 매번 하던 SpringBoot 의존성 추가에 JPA라거나 DB 관련한 드라이버는 제외해야 한다.
또한 properties, yml 역시 db연결 부분을 제외해줘야 한다.
내용추가
로그인 시점에서 Auth 서비스는 입력받은 email을 기반으로 회원이 존재하는지 확인해야 한다.
하지만 DB를 소유하고 있지 않기 때문에 User 서비스의 DB에서 email에 맞는 User 정보를 가져와야 한다.
그리고 가져온 정보를 토대로 JWT를 발급한다.
먼저 UserServiceClient 라는 인터페이스를 생성해준다.
@FeignClient(name = "msa-user-service", url = "http://localhost:8081") // in local environment
public interface UserServiceClient {
@PostMapping ("v1/users/email")
UserDto findUserByEmail(@RequestBody EmailRequestDto email);
}
먼저 코드를 보면 FeignClient라는게 보인다.
잘 정리된 글이 있어 가져왔다.
일단 여기서 간단하게 요약한다면
Feign Client는 Spring Cloud에서 제공하는 HTTP 클라이언트로, REST API 호출을 인터페이스 기반으로 간결하게 구현할 수 있도록 도와주는 라이브러리
일반적인 RestTemplate 또는 WebClient보다 코드가 간단하고, 선언적인 방식으로 API 호출 가능
대충 HTTP 클라이언트의 기능을 간단한 코드로 구현한 내용이라고 생각하면 된다.
@FeignClient(name = "msa-user-service", url = "http://localhost:8081") // in local environment
public interface UserServiceClient {
@PostMapping ("v1/users/email")
UserDto findUserByEmail(@RequestBody EmailRequestDto email);
}
해당 코드를 통해
http://localhost:8081/v1/users/email 에 접근하여 결과를 받을 수 있다는 점이다.
따라서 저 코드를 통해 받는 정보는 위에서 작성했던 회원 조회의 결과값이다.
이제 위에서 구현한 코드를 실제로 사용할 타이밍이다.
@Service
@RequiredArgsConstructor
public class AuthService {
private final UserServiceClient userServiceClient;
private final JwtUtil jwtUtil;
private final PasswordEncoder passwordEncoder;
public String login(LoginRequestDto requestDto) {
// 1. email 을 통해 UserService 에서 UserDto 로 객체 생성
EmailRequestDto emailRequestDto = new EmailRequestDto(requestDto.getEmail());
UserDto user = userServiceClient.findUserByEmail(emailRequestDto);
// 2. UserDto 의 password 와 request 의 password 를 비교
if (!passwordEncoder.matches(requestDto.getPassword(), user.getPassword())) {
throw new CustomException(ErrorCode.AUTHENTICATION_FAILED);
}
// 3. JWT 토큰 생성
return jwtUtil.generateToken(user.getEmail());
}
}