SpringBoot/보안과 인증

로그인 & 회원가입 구현

DEVLIB 2025. 4. 15. 10:24
728x90

로그인 & 회원가입 구현 개요

기술 스택

  • Spring Boot
  • Spring Security
  • H2 / MySQL
  • JPA
  • BCryptPasswordEncoder (비밀번호 암호화)

1. 의존성 설정 (build.gradle)

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    runtimeOnly 'com.h2database:h2' // 또는 mysql
}

2. 회원 Entity

@Entity
public class Member {
    @Id @GeneratedValue
    private Long id;

    private String username;

    private String password;

    private String role; // ex: ROLE_USER
}

3. 회원가입 DTO

public class MemberDto {
    private String username;
    private String password;
}

4. MemberRepository

public interface MemberRepository extends JpaRepository<Member, Long> {
    Optional<Member> findByUsername(String username);
}

5. 비밀번호 암호화 (Config)

@Configuration
public class SecurityConfig {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    // 기타 Security 설정 생략...
}

6. 사용자 인증용 UserDetailsService 구현

@Service
public class CustomUserDetailsService implements UserDetailsService {

    private final MemberRepository memberRepository;

    public CustomUserDetailsService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Member member = memberRepository.findByUsername(username)
                .orElseThrow(() -> new UsernameNotFoundException("사용자 없음"));

        return User.builder()
                .username(member.getUsername())
                .password(member.getPassword())
                .roles("USER")
                .build();
    }
}

7. 회원가입 서비스

@Service
public class MemberService {

    private final MemberRepository memberRepository;
    private final PasswordEncoder passwordEncoder;

    public MemberService(MemberRepository memberRepository, PasswordEncoder passwordEncoder) {
        this.memberRepository = memberRepository;
        this.passwordEncoder = passwordEncoder;
    }

    public void register(MemberDto dto) {
        if (memberRepository.findByUsername(dto.getUsername()).isPresent()) {
            throw new IllegalArgumentException("이미 존재하는 사용자입니다.");
        }

        Member member = new Member();
        member.setUsername(dto.getUsername());
        member.setPassword(passwordEncoder.encode(dto.getPassword()));
        member.setRole("ROLE_USER");

        memberRepository.save(member);
    }
}

8. 컨트롤러

@Controller
@RequiredArgsConstructor
public class AuthController {

    private final MemberService memberService;

    @GetMapping("/login")
    public String login() {
        return "login";
    }

    @GetMapping("/signup")
    public String signupForm(Model model) {
        model.addAttribute("memberDto", new MemberDto());
        return "signup";
    }

    @PostMapping("/signup")
    public String signup(@ModelAttribute MemberDto memberDto) {
        memberService.register(memberDto);
        return "redirect:/login";
    }
}

9. Thymeleaf 템플릿 예시

login.html

<form method="post" action="/login">
  <input type="text" name="username" placeholder="아이디" />
  <input type="password" name="password" placeholder="비밀번호" />
  <button type="submit">로그인</button>
</form>

signup.html

<form method="post" th:action="@{/signup}" th:object="${memberDto}">
  <input type="text" th:field="*{username}" placeholder="아이디" />
  <input type="password" th:field="*{password}" placeholder="비밀번호" />
  <button type="submit">회원가입</button>
</form>

마무리 요약

기능 구현 요소
회원가입 DTO → Service → 암호화 → Repository 저장
로그인 스프링 시큐리티 기본 폼 → DB 사용자 인증
비밀번호 암호화 BCryptPasswordEncoder
사용자 인증 UserDetailsService 구현
보안 적용 모든 경로에 인증 적용, /login, /signup만 허용
LIST