티스토리 뷰

반응형

Spring Boot + Spring Security 환경에서 표준 방식으로 로그인 기능을 구현하는 방법을 설명합니다.

1. 개발 환경

항목 버전
Java 17 이상
Spring Boot 3.x
Spring Security 6.x
DB MariaDB / MySQL
Build Tool Gradle

2. 로그인 구조

Client Browser
    ↓
HTTPS 요청
    ↓
Spring Security Filter
    ↓
AuthenticationManager
    ↓
UserDetailsService
    ↓
DB 사용자 조회
    ↓
BCrypt 비밀번호 검증
    ↓
인증 성공 / 실패

3. 의존성 추가

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-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

    runtimeOnly 'com.mysql:mysql-connector-j'

    testImplementation 'org.springframework.security:spring-security-test'
}

4. 사용자 테이블 생성

users 테이블

CREATE TABLE users (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(100) NOT NULL UNIQUE,
    password VARCHAR(255) NOT NULL,
    role VARCHAR(50) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

5. 비밀번호 암호화 방식

Spring Security에서는 기본적으로 BCryptPasswordEncoder 사용을 권장합니다.

  • 단방향 해시
  • Salt 자동 적용
  • Rainbow Table 공격 방어
  • 권장 Cost Factor 적용 가능

암호화 예제

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

회원가입 시 암호화 저장

String encodedPassword = passwordEncoder.encode(rawPassword);

6. Entity 생성

User Entity

@Entity
@Table(name = "users")
@Getter
@Setter
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String username;

    private String password;

    private String role;
}

7. Repository 생성

@Repository
public interface UserRepository extends JpaRepository<User, Long> {

    Optional<User> findByUsername(String username);
}

8. UserDetailsService 구현

Spring Security 인증 과정에서 사용자 정보를 조회하는 핵심 클래스입니다.

@Service
@RequiredArgsConstructor
public class CustomUserDetailsService implements UserDetailsService {

    private final UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException {

        User user = userRepository.findByUsername(username)
                .orElseThrow(() ->
                        new UsernameNotFoundException("사용자 없음"));

        return org.springframework.security.core.userdetails.User
                .builder()
                .username(user.getUsername())
                .password(user.getPassword())
                .roles(user.getRole())
                .build();
    }
}

9. Security 설정

SecurityConfig.java

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {

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

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http)
            throws Exception {

        http
            .csrf(csrf -> csrf.disable())

            .authorizeHttpRequests(auth -> auth
                .requestMatchers(
                    "/",
                    "/login",
                    "/join"
                ).permitAll()
                .anyRequest().authenticated()
            )

            .formLogin(form -> form
                .loginPage("/login")
                .loginProcessingUrl("/login-process")
                .defaultSuccessUrl("/main", true)
                .failureUrl("/login?error=true")
                .permitAll()
            )

            .logout(logout -> logout
                .logoutUrl("/logout")
                .logoutSuccessUrl("/")
            );

        return http.build();
    }
}

10. 로그인 Controller

@Controller
public class LoginController {

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

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

반응형

11. 로그인 화면 구현

login.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Login</title>
</head>
<body>

<h2>로그인</h2>

<form method="post" action="/login-process">

    <div>
        <input type="text"
               name="username"
               placeholder="아이디">
    </div>

    <div>
        <input type="password"
               name="password"
               placeholder="비밀번호">
    </div>

    <button type="submit">로그인</button>

</form>

</body>
</html>

12. HTTPS 통신 암호화

로그인 기능에서는 반드시 HTTPS 사용이 권장됩니다. 비밀번호는 TLS 암호화 채널을 통해 전송되어야 합니다.

HTTPS 적용 이유

  • 비밀번호 평문 탈취 방지
  • 세션 하이재킹 방어
  • MITM 공격 방지
  • 쿠키 탈취 방지

application.yml 설정

server:
  ssl:
    enabled: true
    key-store: classpath:keystore.p12
    key-store-password: password
    key-store-type: PKCS12

13. 세션 보안 설정

권장 설정

http
    .sessionManagement(session -> session
        .sessionFixation().migrateSession()
        .maximumSessions(1)
    );
  • 세션 고정 공격(Session Fixation) 방어
  • 중복 로그인 제한

14. CSRF 방어

운영 환경에서는 CSRF 비활성화보다 활성화를 권장합니다.

기본 사용 예제

http.csrf(Customizer.withDefaults());

15. 보안 권장 사항

항목 설명
BCrypt 사용 비밀번호 단방향 암호화
HTTPS 사용 통신 구간 암호화
CSRF 방어 위조 요청 방어
세션 고정 방어 인증 세션 탈취 방어
XSS 방어 출력값 Escape 처리
로그인 실패 제한 Brute Force 공격 방어
보안 헤더 적용 CSP, HSTS, X-Frame-Options

16. 보안 헤더 적용

http
    .headers(headers -> headers
        .httpStrictTransportSecurity(hsts ->
            hsts.includeSubDomains(true)
        )
        .frameOptions(frame ->
            frame.sameOrigin()
        )
    );

17. 로그인 성공 흐름

1. 사용자가 ID/PW 입력
2. HTTPS 전송
3. Spring Security 인증 처리
4. BCrypt 해시 비교
5. 인증 성공
6. SecurityContext 저장
7. Session 생성
8. 메인 페이지 이동

 

참고 공식 문서

    • Spring Boot Official Docs
      https://spring.io/projects/spring-boot
    • Spring Security Reference
      https://docs.spring.io/spring-security/reference/index.html

 

 

#SpringBoot
#SpringSecurity
#SpringBootLogin
#JavaLogin
#SpringBootSecurity
#HTTPS
#BCrypt
#SpringAuthentication
#LoginSecurity
#CSRF
#SessionSecurity
#JavaWebSecurity
#SpringBootTutorial
#OAuth2
#JWT

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/06   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함
반응형