BindProject

[Backend] Auth모듈 :사용자 등록 로직의 책임 분리와 유효성 검사 개선

dding-shark 2025. 6. 18. 22:03
728x90

사용자 등록 로직의 책임 분리와 유효성 검사 개선

1. 도입

사용자 등록(Sign-up)은 인증(Auth) 시스템의 핵심이다. 그러나 이 과정을 단순히 "사용자 저장"으로만 처리하면 곧 유지보수와 확장성에서 문제를 겪게 된다.
이 글에서는 다음과 같은 개선을 목표로 AuthService를 리팩토링한 과정을 설명한다:

  • 유효성 검사를 Validator 인터페이스로 추상화
  • 기본 권한 부여 로직을 별도의 UserRoleGrantService로 분리
  • 비즈니스 검증 로직에 따라 커스텀 예외 처리

2. 설계 목표

  • 단일 책임 원칙(SRP) 준수를 통한 서비스 계층의 응집도 향상
  • 유효성 검사 로직 재사용성 확보 및 테스트 용이성 강화
  • 역할(Role) 부여 로직을 별도 서비스로 분리하여 관리 편의성 확보

3. 설계 고려사항

  • 유효성 검사 기준은 정책 변경에 따라 바뀔 수 있으므로, 조건들을 하드코딩하지 않고 인터페이스로 추상화
  • 역할(Role) 부여 책임은 시스템의 권한 모델 변경과 밀접하므로 UserRoleGrantService로 별도 분리
  • 실패 시점에서 적절한 예외를 AuthException으로 추상화하고, 오류 코드를 AuthErrorCode enum으로 관리

4. 구현 설명

유효성 검사 구조

public interface Validator<T> {
    boolean validate(T target);
    ValidatorType support();
}

ValidatorFactoryMap<ValidatorType, Validator<?>>으로 주입받은 컴포넌트 중 support()로 타입을 판별해 동작한다.

emailValidator.validate("user@example.com")  // true or false

사용자 등록 로직 (AuthService)

@Transactional
public void registerUser(SignUpRequest req) {
    validateUser(req);

    User user = User.builder()
        .id(snowflake.nextId())
        .email(req.getEmail())
        .password(passwordEncoder.encode(req.getPassword()))
        .provider(ProviderList.SYSTEM)
        .createdAt(LocalDateTime.now())
        .isEmailVerified(false)
        .isDeleted(false)
        .build();

    userRepository.save(user);
    userRoleGrantService.grantDefaultRole(user);
}

권한 부여 서비스 분리

public void grantRole(User user, User granter, UserRoleType role) {
    ensureGranterHasPrivilege(granter); // 역할 체크
    UserRole target = userRoleRepository.findByUser(user)
        .orElseThrow(() -> new AuthException(USER_ROLE_NOT_FOUND));

    target.setRole(role);
    target.setGrantedAt(LocalDateTime.now());
    target.setGrantedBy(granter.getId());
    userRoleRepository.save(target);
}

5. 테스트 전략

  • AuthServiceTest에서는 회원가입 유효성 검증 및 중복 이메일, 잘못된 포맷 등 예외 상황 커버
  • UserRoleGrantServiceTest에서는 User, Guest 사용자가 관리자 권한을 부여하려 할 때 예외 발생 여부 확인
  • ValidatorFactoryTest를 통해 등록된 Validator가 잘 매핑되고 동작하는지 검증

6. 회고 및 확장 가능성

얻은 것

  • 역할 부여 책임이 독립되면서 도메인 지식이 분산되지 않고 한 곳에 집중
  • 새로운 역할 정책을 도입하거나 변경하더라도 UserRoleGrantService만 수정하면 된다
  • 유효성 검증이 Validator 패턴으로 추상화되어 테스트가 쉬워지고 확장성이 증가

앞으로의 방향

  • Validator를 AOP로 감싸거나, 애노테이션 기반으로 추상화 가능 (ex. @ValidPassword)
  • 권한 부여 시 ROLE_ADMIN 이상의 인증이 필요한 정책으로 확장 가능
  • 감사(Audit) 로그 저장 또는 이벤트 발행으로 grantRole() 동작을 추적할 수 있도록 확장 가능

마무리

이러한 리팩토링을 통해 책임을 명확히 분리하고, 변경에 강한 구조로 전환할 수 있었다.
복잡해지는 인증 시스템에서 핵심은 결국 확장 가능한 구조와 명확한 책임 분리다.


728x90