[Spring Security] Spring Boot + Spring Security를 이용한 회원가입 구현하기

kingkang·2024년 12월 28일

🌸 Spring

목록 보기
2/2
post-thumbnail

이번 포스팅에서는 Spring BootSpring Security를 함께 사용하여 구현한 회원가입 프로세스에 대해 자세히 알아보겠습니다 🚀


전체 구조

회원가입 구현은 다음과 같은 계층 구조로 이루어져 있습니다:

  • Controller (웹 요청 처리)
  • Service (비즈니스 로직)
  • Repository (데이터 접근)
  • Entity (데이터 모델)

Entity 구조

@Entity
@Table(name = "tbl_user")
@Data
public class User {
    @Id  // Primary Key 지정
    @GeneratedValue(strategy = GenerationType.IDENTITY)  // Auto Increment
    @Column(name = "user_pk")
    private long userPk;

    @Column(name = "user_id", nullable = false, unique = true)
    private String userId;

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

    @Column(name = "user_email", nullable = false, unique = true)
    private String userEmail;

    @Column(name = "user_nickname", nullable = false, unique = true)
    private String userNickname;

    @Column(name = "user_role")
    private String userRole = "ROLE_USER";  // Spring Security의 기본 권한
}
  • @Entity : JPA 엔티티임을 나타냄
  • @Table : 실제 DB 테이블 이름 지정
  • @Data : getter/setter/toString 등 자동 생성
  • nullable = false로 필수 입력값 지정
  • unique = true로 중복 방지

UserCreateRequest DTO

클라이언트로부터 회원가입 데이터를 받는 DTO

@Data
public class UserCreateRequest {
    private String userId;
    private String userPw;
    private String userEmail;
    private String userNickname;
}

UserRepository

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    boolean existsByUserId(String userId);
    boolean existsByUserEmail(String userEmail);
    boolean existsByUserNickname(String userNickname);
    Optional<User> findByUserId(String userId);
    Optional<User> findByUserEmail(String userEmail);
}
  • JpaRepository 상속으로 기본 CRUD 메서드 제공
  • Optional : 사용자 조회 시 결과가 null일 수 있는 경우 사용

Controller 구현

@RestController
public class UserController {
    private final UserService userService;

    @PostMapping("/auth/join")  // /auth/** 경로로 Spring Security 인증 없이 접근 가능
    public ResponseEntity<?> join(@RequestBody UserCreateRequest request) {
        userService.createUser(request);
        return ResponseEntity.status(HttpStatus.CREATED).body("회원 가입이 완료되었습니다.");
    }
}
  • /auth/join 엔드포인트로 POST 요청 처리
  • @RequestBody로 JSON 데이터를 DTO로 변환
  • 성공 시 201 Created 상태코드 반환
  • 생성자 주입으로 UserService 의존성 주입

Service 구현

@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
    private final UserRepository userRepository;
    private final BCryptPasswordEncoder passwordEncoder;  // Spring Security의 암호화 도구
    private final ModelMapper modelMapper;

    @Override
    @Transactional
    public void createUser(UserCreateRequest request) {
        // 중복 검사
        checkDuplicateUser(request);

        // DTO -> Entity 변환
        User user = modelMapper.map(request, User.class);

        // Spring Security의 BCrypt로 비밀번호 암호화
        user.setUserPw(passwordEncoder.encode(request.getUserPw()));
        // Spring Security의 기본 사용자 권한 설정
        user.setUserRole("ROLE_USER");

        userRepository.save(user);
    }
    
     private void checkDuplicateUser(UserCreateRequest request) {
        List<String> errors = new ArrayList<>();
        if (userRepository.existsByUserId(request.getUserId())) {
            errors.add("이미 사용 중인 아이디입니다.");
        }
        // ... 이메일, 닉네임 중복 검사
        
        if (!errors.isEmpty()) {
            throw new DuplicateUserException(String.join(", ", errors));
        }
    }
}
  • @Transactional로 트랜잭션 처리
  • @RequiredArgsConstructor로 final 필드 생성자 주입
  • ModelMapper로 DTO -> Entity 변환 자동화
  • BCryptPasswordEncoder로 비밀번호 암호화
  • 중복 검사 로직을 별도 메서드로 분리
  • 여러 중복 오류를 한 번에 반환하도록 구현

Spring Security 관련 주요 특징

비밀번호 암호화

  • BCryptPasswordEncoder를 사용하여 안전한 비밀번호 해싱
  • 암호화된 비밀번호는 복호화가 불가능

권한 관리

  • ROLE_USER와 같은 Spring Security의 권한 체계 사용
  • 추후 @PreAuthorize 등을 통한 메소드 레벨 보안 적용 가능

보안 설정

  • /auth/** 경로는 인증 없이 접근 가능
  • 나머지 경로는 인증 필요

개선이 필요한 부분

  • 입력값 검증 (Bean Validation)
  • 예외 처리 개선
  • OAuth2 소셜 로그인을 위한 필드 추가
profile
꿈을 꾸물꾸물 꾸지 말자!

0개의 댓글