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

[FEAT] 번호 인증 검사 기능 구현 #15

Open
wants to merge 14 commits into
base: dev
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,9 +1,11 @@
package sopt.makers.authentication.application.auth.api;

import sopt.makers.authentication.application.auth.dto.request.AuthRequest;
import sopt.makers.authentication.application.auth.dto.response.AuthResponse;
import sopt.makers.authentication.support.code.domain.success.AuthSuccess;
import sopt.makers.authentication.support.common.api.BaseResponse;
import sopt.makers.authentication.usecase.auth.port.in.CreatePhoneVerificationUsecase;
import sopt.makers.authentication.usecase.auth.port.in.VerifyPhoneVerificationUsecase;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
Expand All @@ -18,6 +20,7 @@
public class AuthApiController implements AuthApi {

private final CreatePhoneVerificationUsecase createVerificationUsecase;
private final VerifyPhoneVerificationUsecase verifyVerificationUsecase;

@Override
@PostMapping("/phone")
Expand All @@ -32,6 +35,10 @@ public ResponseEntity<BaseResponse<?>> createPhoneVerification(
@PostMapping("/verify/phone")
public ResponseEntity<BaseResponse<?>> verifyPhoneVerification(
AuthRequest.VerifyPhoneVerification phoneVerification) {
return null;
boolean result = verifyVerificationUsecase.verify(phoneVerification.toCommand());
return ResponseEntity.status(AuthSuccess.CREATE_PHONE_VERIFICATION.getStatus().value())
.body(
BaseResponse.ofSuccess(
AuthSuccess.CREATE_PHONE_VERIFICATION, new AuthResponse.VerifyResult(result)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import sopt.makers.authentication.domain.auth.PhoneVerificationType;
import sopt.makers.authentication.usecase.auth.port.in.CreatePhoneVerificationUsecase.CreateVerificationCommand;
import sopt.makers.authentication.usecase.auth.port.in.VerifyPhoneVerificationUsecase.VerifyVerificationCommand;

import lombok.RequiredArgsConstructor;

Expand All @@ -17,5 +18,14 @@ public CreateVerificationCommand toCommand() {
}
}

public record VerifyPhoneVerification(String name, String number, String code) {}
public record VerifyPhoneVerification(
String name, String number, String code, String verificationTypeName) {
public VerifyVerificationCommand toCommand() {
return new VerifyVerificationCommand(
this.name,
this.number,
this.code,
PhoneVerificationType.valueOf(this.verificationTypeName));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

import static lombok.AccessLevel.PRIVATE;

import com.fasterxml.jackson.annotation.JsonProperty;

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor(access = PRIVATE)
public final class AuthResponse {}
public final class AuthResponse {

public record VerifyResult(@JsonProperty("isVerified") boolean isVerified) {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p3

회원가입에서 번호 인증을 사용하게 되면 운영진이 제공해준 사용자 정보를 식별할 수 있는 값도 전달되어야 할 것 같은데 어떻게 생각하시나요? 컨트롤러를 분리하는게 좋을지 response에서 필드를 추가해 재사용하는게 좋을지 고민되어 일단 response에 남겨봅니다!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오호옷!!

식별 데이터라 하심은
임원진으로부터 전달받은 "신규회원 csv를 저장한 테이블"에서의 ID를 넘겨주자는 거죠?!

전 좋은 것 같습니다!!
그래야만 소셜 인증 요청 시, 인증된 csv 내 신규회원 식별 값을 함께 넘겨 해당 DB에서 삭제까지 용이하게 할 수 있겠군요
(저희가 논의했을 땐, 소셜인증까지 완료했을 때만 csv 저장 데이터를 삭제하자고 했었으니까!!)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 근데 고려되어야 할 점이 회원가입 시점에서는 csv 파일을 저장한 id를 넘겨주셔야하지만 소셜계정 변경을 위해 번호인증을 한 경우에는 실제 유저의 id를 넘겨주시거나 다른 값(현재 사용되고 있는 socialPlaltformId 등)을 전달 해야할 것 같은데 어떻게 생각하시나요?

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package sopt.makers.authentication.database;
yummygyudon marked this conversation as resolved.
Show resolved Hide resolved

import sopt.makers.authentication.database.rdb.entity.auth.PhoneVerificationEntity;
import sopt.makers.authentication.database.rdb.repository.auth.PhoneVerificationRegister;
import sopt.makers.authentication.database.rdb.repository.auth.PhoneVerificationRemover;
import sopt.makers.authentication.database.rdb.repository.auth.PhoneVerificationRetriever;
import sopt.makers.authentication.domain.auth.PhoneVerification;
import sopt.makers.authentication.usecase.auth.port.out.PhoneVerificationRepository;

import org.springframework.stereotype.Repository;

import lombok.RequiredArgsConstructor;

@Repository
@RequiredArgsConstructor
public class PhoneVerificationRepositoryImpl implements PhoneVerificationRepository {

private final PhoneVerificationRegister register;
private final PhoneVerificationRetriever retriever;
private final PhoneVerificationRemover remover;
yummygyudon marked this conversation as resolved.
Show resolved Hide resolved

@Override
public PhoneVerification create(PhoneVerification phoneVerification) {
PhoneVerificationEntity createdEntity = register.register(phoneVerification);
return createdEntity.toDomain();
}

@Override
public PhoneVerification findByPhoneVerification(PhoneVerification phoneVerification) {
PhoneVerificationEntity phoneVerificationEntity = retriever.find(phoneVerification);
return phoneVerificationEntity.toDomain();
}

@Override
public void deletedByPhoneVerification(PhoneVerification phoneVerification) {
remover.remove(phoneVerification);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package sopt.makers.authentication.database.rdb.entity;
package sopt.makers.authentication.database.rdb.entity.auth;

import static lombok.AccessLevel.PRIVATE;
import static lombok.AccessLevel.PROTECTED;
Expand All @@ -22,7 +22,7 @@
@AllArgsConstructor(access = PRIVATE)
public class PhoneVerificationEntity extends BaseEntity {

@Column(name = "name", nullable = false)
@Column(name = "name")
private String name;

@Column(name = "phone", nullable = false)
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package sopt.makers.authentication.database.rdb.repository.auth;

import sopt.makers.authentication.database.rdb.entity.auth.PhoneVerificationEntity;
import sopt.makers.authentication.domain.auth.PhoneVerificationType;

import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;

interface PhoneVerificationJpaRepository extends JpaRepository<PhoneVerificationEntity, Long> {

Optional<PhoneVerificationEntity> findByPhoneAndCodeAndType(
String phone, String code, PhoneVerificationType type);

void deleteByNameAndPhoneAndCodeAndType(
String name, String phone, String code, PhoneVerificationType type);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package sopt.makers.authentication.database.rdb.repository.auth;

import sopt.makers.authentication.database.rdb.entity.auth.PhoneVerificationEntity;
import sopt.makers.authentication.domain.auth.PhoneVerification;

import jakarta.transaction.Transactional;

import org.springframework.stereotype.Component;

import lombok.RequiredArgsConstructor;

@Component
@Transactional
@RequiredArgsConstructor
public class PhoneVerificationRegister {

private final PhoneVerificationJpaRepository jpaRepository;

public PhoneVerificationEntity register(PhoneVerification phoneVerification) {
PhoneVerificationEntity entity = PhoneVerificationEntity.fromDomain(phoneVerification);
return jpaRepository.save(entity);
}

public PhoneVerificationEntity register(final long id, PhoneVerification phoneVerification) {
PhoneVerificationEntity entity = PhoneVerificationEntity.fromDomain(id, phoneVerification);
return jpaRepository.save(entity);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package sopt.makers.authentication.database.rdb.repository.auth;

import sopt.makers.authentication.domain.auth.PhoneVerification;

import jakarta.transaction.Transactional;

import org.springframework.stereotype.Component;

import lombok.RequiredArgsConstructor;

@Component
@Transactional
@RequiredArgsConstructor
public class PhoneVerificationRemover {

private final PhoneVerificationJpaRepository jpaRepository;

public void remove(PhoneVerification phoneVerification) {
jpaRepository.deleteByNameAndPhoneAndCodeAndType(
phoneVerification.getName(),
phoneVerification.getPhone(),
phoneVerification.getVerificationCode().getCode(),
phoneVerification.getVerificationType());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package sopt.makers.authentication.database.rdb.repository.auth;

import sopt.makers.authentication.database.rdb.entity.auth.PhoneVerificationEntity;
import sopt.makers.authentication.domain.auth.PhoneVerification;
import sopt.makers.authentication.support.code.domain.failure.AuthFailure;
import sopt.makers.authentication.support.exception.domain.AuthException;

import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import lombok.RequiredArgsConstructor;

@Component
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class PhoneVerificationRetriever {

private final PhoneVerificationJpaRepository jpaRepository;

public PhoneVerificationEntity find(PhoneVerification phoneVerification) {
return jpaRepository
.findByPhoneAndCodeAndType(
phoneVerification.getPhone(),
phoneVerification.getVerificationCode().getCode(),
phoneVerification.getVerificationType())
.orElseThrow(() -> new AuthException(AuthFailure.NOT_FOUND_PHONE_VERIFICATION));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
import java.util.Random;

import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@Builder(access = PRIVATE)
@RequiredArgsConstructor(access = PRIVATE)
@EqualsAndHashCode
public class PhoneVerification {

private final String name;
Expand Down Expand Up @@ -40,6 +42,7 @@ public static PhoneVerification create(String name, String phone, PhoneVerificat
}

@Getter
@EqualsAndHashCode
public static class VerificationCode {
private static final int CODE_SIZE = 6;
private final String code;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@
@Getter
@RequiredArgsConstructor(access = PRIVATE)
public enum AuthFailure implements FailureCode {
// 400
INVALID_SOCIAL_PLATFORM(HttpStatus.BAD_REQUEST, "지원하지 않는 소셜 플랫폼입니다"),

// 404
NOT_FOUND_PHONE_VERIFICATION(HttpStatus.NOT_FOUND, "존재하지 않는 번호 인증 이력입니다."),
;
private final HttpStatus status;
private final String message;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
@Getter
@RequiredArgsConstructor(access = PRIVATE)
public enum AuthSuccess implements SuccessCode {
VERIFY_PHONE_VERIFICATION(HttpStatus.OK, "번호 인증에 성공했습니다."),

CREATE_PHONE_VERIFICATION(HttpStatus.CREATED, "번호 인증 생성에 성공했습니다."),
;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package sopt.makers.authentication.usecase.auth.port.in;

import sopt.makers.authentication.domain.auth.PhoneVerificationType;

public interface VerifyPhoneVerificationUsecase {

boolean verify(VerifyVerificationCommand command);

record VerifyVerificationCommand(
String name, String phone, String code, PhoneVerificationType verificationType) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,9 @@

public interface PhoneVerificationRepository {

PhoneVerification save(PhoneVerification phoneVerification);
PhoneVerification create(PhoneVerification phoneVerification);

PhoneVerification findByPhoneVerification(PhoneVerification phoneVerification);

void deletedByPhoneVerification(PhoneVerification phoneVerification);
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public PhoneVerification create(CreateVerificationCommand command) {
convertCodeToMessage(phoneVerification.getVerificationCode().getCode()));

messageSendPort.sendMessage(verificationMessage);
return verificationRepository.save(phoneVerification);
return verificationRepository.create(phoneVerification);
}

private String convertCodeToMessage(String code) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package sopt.makers.authentication.usecase.auth.service;

import sopt.makers.authentication.domain.auth.PhoneVerification;
import sopt.makers.authentication.usecase.auth.port.in.VerifyPhoneVerificationUsecase;
import sopt.makers.authentication.usecase.auth.port.out.PhoneVerificationRepository;

import org.springframework.stereotype.Service;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class VerifyVerificationService implements VerifyPhoneVerificationUsecase {
private final PhoneVerificationRepository phoneVerificationRepository;

@Override
public boolean verify(VerifyVerificationCommand command) {
PhoneVerification targetVerification =
PhoneVerification.of(
command.name(), command.phone(), command.verificationType(), command.code());
PhoneVerification findVerification =
phoneVerificationRepository.findByPhoneVerification(targetVerification);
boolean isVerified = targetVerification.equals(findVerification);

if (isVerified) {
phoneVerificationRepository.deletedByPhoneVerification(findVerification);
yummygyudon marked this conversation as resolved.
Show resolved Hide resolved
}
return isVerified;
}
}
Loading