사용자 인증 및 계정 관리 | 일반 사용자 회원가입 API 구현

Faithful Dev·2025년 3월 15일

매장 예약 서비스

목록 보기
1/15

구현한 기능

  • 일반 사용자(고객) 회원가입 API 기능 구현
  • 이메일, 비밀번호, 이름, 전화번호 정보를 받아 회원 등록
  • 중복 이메일, 전화번호 체크 기능
  • 비밀번호 암호화 처리 (BCrypt)
  • 입력값 유효성 검증 (이메일 형식, 비밀번호 길이, 전화번호 형식)

해결한 문제점

Spring Security 설정 업데이트

  • 최신 Spring Security 6 변경사항 반영
  • deprecated된 WebSecurityConfigurerAdapter 대신 SecurityFilterChain 방식 적용

오류 메시지

'WebSecurityConfigurerAdapter' is deprecated

Spring Security 5.7.0부터 WebSecurityConfigurerAdapter가 deprecated 되었다고 한다. WebSecurityConfigurerAdapter를 상속받는 대신 SecurityFilterChain을 @Bean으로 등록하는 방식으로 변경했다.

수정 전 코드

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                // 나머지 설정...
    }
}

수정 후 코드

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .csrf(csrf -> csrf.disable())
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                // 나머지 설정...
        
        return http.build();
    }
}

MySQL 연결 문제

Public Key Retrieval is not allowed
org.hibernate.exception.JDBCConnectionException: unable to obtain isolated JDBC connection [Public Key Retrieval is not allowed] [n/a]

MySQL 8.0 이상 버전에서는 보안 강화를 위해 RSA 공개 키를 사용하여 비밀번호를 암호화하는 기능이 기본적으로 활성화되어 있다고 한다. 이 기능을 사용하기 위해서는 JDBC URL에 명시적으로 allowPublicKeyRetrieval=true 옵션을 추가해야 한다고.

수정 전 코드

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/reservation_db?useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8

수정 후 코드

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/reservation_db?useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8&allowPublicKeyRetrieval=true

Docker 컨테이너 MySQL 포트 매핑 문제

Access denied for user 'root'@'192.168.65.1' (using password: YES)
org.hibernate.exception.GenericJDBCException: unable to obtain isolated JDBC connection

수강 중인 강의 프로젝트에서 3306 포트를 이미 사용하고 있어서 Docker Compose 설정할 때 MySQL 컨테이너의 내부 포트(3306)를 호스트의 3307 포트로 매핑했었는데, 애플리케이션 설정할 때 3306 포트로 접속을 시도하고 있었다. application.yml 파일의 데이터베이스 연결 URL에서 포트를 3306에서 3307로 변경하여 Docker 컨테이너의 포트 매핑과 일치시켰다.

docker-compose.yml

services:
  mysql:
    ports:
      - "3307:3306"  # 호스트의 3307 포트를 컨테이너의 3306 포트로 매핑

수정 전 application.yml

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/reservation_db?useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8&allowPublicKeyRetrieval=true

수정 후 application.yml

spring:
  datasource:
    url: jdbc:mysql://localhost:3307/reservation_db?useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8&allowPublicKeyRetrieval=true

코드 스냅샷

@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
public class UserController {
    
    private final UserService userService;
    
    /**
     * 일반 사용자 회원가입 API
     * @param request 회원가입 요청 정보
     * @return 회원가입 결과 응답
     */
    @PostMapping("/signup")
    public ResponseEntity<ApiResponse<UserDto.SignUpResponse>> signUp(
            @Valid @RequestBody UserDto.SignUpRequest request) {
        
        UserDto.SignUpResponse response = userService.signUp(request);
        
        return ResponseEntity.status(HttpStatus.CREATED)
                .body(ApiResponse.success("회원가입이 성공적으로 완료되었습니다.", response));
    }
}
@Service
@RequiredArgsConstructor
public class UserService {
    
    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;
    
    /**
     * 일반 사용자 회원가입 처리 메서드
     * @param request 회원가입 요청 정보
     * @return 회원가입 결과 정보
     */
    @Transactional
    public UserDto.SignUpResponse signUp(UserDto.SignUpRequest request) {
        // 이메일 중복 확인
        if (userRepository.existsByEmail(request.getEmail())) {
            throw new CustomException(ErrorCode.EMAIL_ALREADY_EXISTS);
        }
        
        // 전화번호 중복 확인
        if (userRepository.existsByPhone(request.getPhone())) {
            throw new CustomException(ErrorCode.PHONE_ALREADY_EXISTS);
        }
        
        // 사용자 객체 생성 및 저장
        User user = User.builder()
                .email(request.getEmail())
                .password(passwordEncoder.encode(request.getPassword())) // 비밀번호 암호화
                .name(request.getName())
                .phone(request.getPhone())
                .role(UserRole.ROLE_USER) // 일반 사용자 권한 설정
                .active(true) // 기본적으로 활성화 상태로 설정
                .build();
        
        // DB에 저장
        User savedUser = userRepository.save(user);
        
        // 응답 객체 생성 및 반환
        return UserDto.SignUpResponse.builder()
                .userId(savedUser.getId())
                .email(savedUser.getEmail())
                .name(savedUser.getName())
                .phone(savedUser.getPhone())
                .role(savedUser.getRole())
                .build();
    }
}

Postman 테스트


구현 예정

  • 파트너(점장) 회원가입 API
  • 로그인 API (JWT 토큰 발급)
  • 회원정보 조회/수정 API
profile
Turning Vision into Reality.

0개의 댓글