본문 바로가기
Spring/09. spring-security

Form-Login

by 989898 2025. 3. 4.

Spring Security의 폼 로그인(Form Login) 과정과 함께 제공된 그림을 기반으로 설명드리겠습니다. 그림은 인증 요청이 처리되는 과정을 단계별로 시각화한 것으로, 각각의 흐름을 이해하기 쉽게 풀어보겠습니다.

1. 첫 번째 그림: 인증되지 않은 사용자가 로그인 폼으로 리디렉션되는 과정

그림 설명

이 그림은 사용자가 인증되지 않은 상태에서 보호된 리소스(예: /private)에 접근하려고 할 때, Spring Security가 어떻게 로그인 페이지로 리디렉션하는지 보여줍니다.

단계별 흐름

  1. 사용자의 요청 (GET /private)
    사용자가 /private와 같은 보호된 리소스에 접근하려고 요청을 보냅니다. 하지만 이 사용자는 아직 인증되지 않았습니다.
  2. FilterSecurityInterceptor에서 접근 거부
    Spring Security의 FilterSecurityInterceptor는 요청을 확인하고, 사용자가 인증되지 않았음을 감지합니다. 이때, AccessDeniedException이 발생합니다.
  3. ExceptionTranslationFilter가 로그인 페이지로 리디렉션
    ExceptionTranslationFilter는 발생한 예외를 처리하며, 설정된 AuthenticationEntryPoint를 통해 사용자에게 로그인 페이지(/login)로 이동하라는 응답을 보냅니다. 여기서 기본적으로 사용되는 엔트리 포인트는 LoginUrlAuthenticationEntryPoint입니다.
  4. 브라우저가 로그인 페이지 요청 (GET /login)
    브라우저는 Spring Security가 지정한 로그인 페이지(/login)로 이동합니다.
  5. 로그인 페이지 렌더링 (login.html)
    애플리케이션은 로그인 폼이 포함된 HTML 페이지를 렌더링하여 사용자에게 보여줍니다. 사용자는 이 폼에 아이디와 비밀번호를 입력할 수 있습니다.

2. 두 번째 그림: 사용자 인증 과정

그림 설명

이 그림은 사용자가 아이디와 비밀번호를 제출한 후, Spring Security가 이를 처리하고 인증 여부를 결정하는 과정을 보여줍니다.

단계별 흐름

  1. UsernamePasswordAuthenticationFilter가 요청 처리
    사용자가 로그인 폼에 아이디와 비밀번호를 입력하고 제출하면, UsernamePasswordAuthenticationFilter가 HTTP 요청에서 해당 정보를 추출합니다. 추출된 정보는 UsernamePasswordAuthenticationToken 객체로 변환됩니다.
  2. AuthenticationManager에 인증 요청 전달
    생성된 토큰은 AuthenticationManager에게 전달됩니다. AuthenticationManager는 등록된 여러 AuthenticationProvider(예: DaoAuthenticationProvider)를 통해 실제 인증 작업을 수행합니다.
    • UserDetailsService를 통해 사용자 정보를 조회합니다.
    • 입력된 비밀번호와 저장된 비밀번호를 비교하여 인증 성공 여부를 판단합니다.
  3. 인증 실패 시
    만약 아이디나 비밀번호가 잘못되었다면, 다음과 같은 일이 발생합니다:
    • SecurityContextHolder 초기화: 현재 보안 컨텍스트를 초기화하여 이전의 인증 정보를 제거합니다.
    • RememberMeServices.loginFail: Remember Me 기능이 설정되어 있다면, 실패 처리를 수행합니다.
    • AuthenticationFailureHandler: 실패 메시지를 반환하거나 실패 페이지로 리디렉션합니다.
  4. 인증 성공 시
    인증이 성공하면 다음 단계가 진행됩니다:
    • SessionAuthenticationStrategy: 새로운 세션을 생성하거나 기존 세션을 관리합니다.
    • SecurityContextHolder: 인증 정보를 보안 컨텍스트에 저장합니다.
    • RememberMeServices.loginSuccess: Remember Me 기능이 설정되어 있다면 성공 처리를 수행합니다.
    • ApplicationEventPublisher: 성공 이벤트(InteractiveAuthenticationSuccessEvent)를 발행합니다.
    • AuthenticationSuccessHandler: 사용자를 원래 요청했던 페이지 또는 기본 페이지로 리디렉션합니다.

코드와 함께 이해하기

기본 폼 로그인 설정:

public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .formLogin(withDefaults()); // 기본 폼 로그인 활성화
    return http.build();
}
 
 

위 코드는 기본 제공되는 로그인 페이지(/login)를 활성화하는 설정입니다.

커스텀 로그인 페이지 설정:

public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .formLogin(form -> form
            .loginPage("/auth/login.do") // 커스텀 로그인 페이지 경로 설정
            .permitAll() // 모든 사용자에게 접근 허용
        );
    return http.build();
}
 
 

위 코드는 /auth/login.do 경로에 커스텀 로그인 페이지를 설정하는 방법입니다.

커스텀 HTML 로그인 폼:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org">
<head>
    <title>Please Log In</title>
</head>
<body>
    <h1>Please Log In</h1>
    <div th:if="${param.error}">
        Invalid username and password.</div>
    <div th:if="${param.logout}">
        You have been logged out.</div>
    <form th:action="@{/auth/loginAction.do}" method="post">
        <div>
            <input type="text" name="username" placeholder="Username"/>
        </div>
        <div>
            <input type="password" name="password" placeholder="Password"/>
        </div>
        <input type="submit" value="Log in" />
    </form>
</body>
</html>
 
 

커스텀 컨트롤러:

@Controller
public class LoginController {
    @GetMapping("/auth/login.do")
    public String login() {
        return "login"; // login.html 템플릿 반환
    }
}
 
 

요약

  1. 첫 번째 그림은 인증되지 않은 사용자가 보호된 리소스에 접근하려고 할 때, Spring Security가 어떻게 로그인 페이지로 리디렉션하는지를 보여줍니다.
  2. 두 번째 그림은 사용자가 아이디와 비밀번호를 제출한 후, Spring Security가 이를 처리하여 인증 성공 또는 실패 여부를 결정하는 과정을 보여줍니다.
  3. Spring Security는 기본 제공되는 로그인 페이지 외에도 커스텀 로그인 페이지를 설정할 수 있으며, 개발자는 이를 통해 사용자 경험을 개선할 수 있습니다.