Spring Security ‐ Username password‐based authentication mechanism - taeyun-ham/andalos GitHub Wiki

Username/Password Authentication

사용자를 인증하는 가장 일반적인 방법 중 하나는 사용자 이름과 비밀번호를 검증하는 것입니다. 스프링 시큐리티는 사용자 이름과 비밀번호를 사용한 인증에 대해 포괄적인 지원을 제공합니다.

Reading the Username & Password

Spring Security는 HttpServletRequest에서 사용자 이름과 비밀번호를 읽기 위해 다음과 같은 내장 메커니즘을 제공합니다.

Section Summary

  • Form
  • Basic
  • Digest

관련있는 필터

UsernamePasswordMechanism-페이지-2

Form Login

스프링 시큐리티는 HTML 폼을 통해 제공되는 사용자 이름과 비밀번호에 대한 지원을 제공합니다. 이 섹션에서는 스프링 시큐리티 내에서 폼 기반 인증이 어떻게 작동하는지에 대한 세부 정보를 제공합니다.

이 섹션에서는 스프링 시큐리티 내에서 폼 기반 로그인이 어떻게 작동하는지 살펴봅니다. 먼저, 사용자가 로그인 폼으로 어떻게 리다이렉트되는지 확인합니다:

loginurlauthenticationentrypoint

앞서 언급된 그림은 우리의 SecurityFilterChain 다이어그램을 바탕으로 합니다.

  1. 먼저, 사용자가 권한이 없는 리소스(/private)에 대해 인증되지 않은 요청을 합니다.
  2. 스프링 시큐리티의 AuthorizationFilter는 인증되지 않은 요청이 거부되었음을 나타내기 위해 AccessDeniedException을 발생시킵니다.
  3. 사용자가 인증되지 않았기 때문에, ExceptionTranslationFilter는 Start Authentication을 시작하고 구성된 AuthenticationEntryPoint를 사용하여 로그인 페이지로 리다이렉트를 보냅니다. 대부분의 경우, AuthenticationEntryPoint는 LoginUrlAuthenticationEntryPoint의 인스턴스입니다.
  4. 브라우저가 리다이렉트된 로그인 페이지를 요청합니다.
  5. 애플리케이션 내의 무언가가 로그인 페이지를 렌더링해야 합니다.

사용자 이름과 비밀번호가 제출되면, UsernamePasswordAuthenticationFilter는 사용자 이름과 비밀번호를 인증합니다. UsernamePasswordAuthenticationFilter는 AbstractAuthenticationProcessingFilter를 확장하므로, 다음 다이어그램은 상당히 유사해 보일 것입니다:

usernamepasswordauthenticationfilter

이 그림은 우리의 SecurityFilterChain 다이어그램을 바탕으로 합니다.

  1. 사용자가 사용자 이름과 비밀번호를 제출하면, UsernamePasswordAuthenticationFilter는 HttpServletRequest 인스턴스에서 사용자 이름과 비밀번호를 추출하여 UsernamePasswordAuthenticationToken을 생성합니다. UsernamePasswordAuthenticationToken은 Authentication의 한 유형입니다.
  2. 다음으로, UsernamePasswordAuthenticationToken은 인증을 위해 AuthenticationManager 인스턴스로 전달됩니다. 사용자 정보가 어떻게 저장되어 있는지에 따라 AuthenticationManager의 세부 사항이 달라집니다.
  3. 인증에 실패하면, 실패입니다.
    1. SecurityContextHolder가 비워집니다.
    1. RememberMeServices.loginFail이 호출됩니다. 리멤버 미(remember me)가 구성되지 않은 경우, 이는 작업 없음입니다. Javadoc에서 RememberMeServices 인터페이스를 참조하세요.
    1. AuthenticationFailureHandler가 호출됩니다. Javadoc에서 AuthenticationFailureHandler 클래스를 참조하세요.
  1. 인증에 성공하면, 성공입니다.
    1. SessionAuthenticationStrategy가 새로운 로그인에 대해 알림을 받습니다. Javadoc에서 SessionAuthenticationStrategy 인터페이스를 참조하세요.
    1. Authentication이 SecurityContextHolder에 설정됩니다. Javadoc에서 SecurityContextPersistenceFilter 클래스를 참조하세요.
    1. RememberMeServices.loginSuccess가 호출됩니다. 리멤버 미가 구성되지 않은 경우, 이는 작업 없음입니다. Javadoc에서 RememberMeServices 인터페이스를 참조하세요.
    1. ApplicationEventPublisher가 InteractiveAuthenticationSuccessEvent를 발행합니다.
    1. AuthenticationSuccessHandler가 호출됩니다. 일반적으로 이는 SimpleUrlAuthenticationSuccessHandler이며, 로그인 페이지로 리다이렉트할 때 ExceptionTranslationFilter에 의해 저장된 요청으로 리다이렉트합니다.

기본적으로 스프링 시큐리티 폼 로그인이 활성화되어 있습니다. 그러나, 서블릿 기반의 구성이 제공되는 즉시, 폼 기반 로그인은 명시적으로 제공되어야 합니다. 다음 예시는 최소한의 명시적 자바 구성을 보여줍니다:

Form Login

public SecurityFilterChain filterChain(HttpSecurity http) {
	http
		.formLogin(withDefaults());
	// ...
}

Login Form - src/main/resources/templates/login.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="@{/login}" 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>

기본 HTML 양식에 대한 몇 가지 핵심 사항이 있습니다.

  • form 은 /login으로 post를 수행해야 합니다.
  • form 에는 CSRF 토큰이 포함되어야 합니다. 이는 Thymeleaf에 의해 자동으로 포함됩니다.
  • form 은 username이라는 이름의 매개변수로 사용자 이름을 지정해야 합니다.
  • form 은 password라는 이름의 매개변수로 비밀번호를 지정해야 합니다.
  • error라는 이름의 HTTP 매개변수가 발견되면, 사용자가 유효한 사용자 이름이나 비밀번호를 제공하지 못했음을 나타냅니다.
  • logout이라는 이름의 HTTP 매개변수가 발견되면, 사용자가 성공적으로 로그아웃했음을 나타냅니다.

추가되는 Filters

  • UsernamePasswordAuthenticationFilter
  • DefaultLoginPageGeneratingFilter
  • DefaultLogoutPageGeneratingFilter
  • LogoutFilter

위 Filter 가 적용되는 절차를 보려면 FormLoginConfigurer 를 보면 됩니다.

Custom Login Form Configuration

public SecurityFilterChain filterChain(HttpSecurity http) {
	http
		.formLogin(form -> form
			.loginPage("/login")
			.permitAll()
		);
	// ...
}

추가되는 Filters

  • UsernamePasswordAuthenticationFilter
  • LogoutFilter

formLogin 설정과 관련있는 객체들

UsernamePasswordMechanism-FormLogin (3)

Basic Authentication

이 섹션에서는 스프링 시큐리티가 서블릿 기반 애플리케이션을 위한 기본 HTTP 인증을 지원하는 방법에 대한 세부 정보를 제공합니다.

이 섹션에서는 스프링 시큐리티 내에서 HTTP 기본 인증이 어떻게 작동하는지 설명합니다. 먼저, WWW-Authenticate 헤더가 인증되지 않은 클라이언트에게 다시 전송되는 것을 볼 수 있습니다: basicauthenticationentrypoint

앞서 언급된 그림은 우리의 SecurityFilterChain 다이어그램을 기반으로 합니다.

  1. 먼저, 사용자가 권한이 없는 리소스 /private에 대해 인증되지 않은 요청을 합니다.
  2. 스프링 시큐리티의 AuthorizationFilter는 인증되지 않은 요청이 거부되었음을 나타내기 위해 AccessDeniedException을 발생시킵니다.
  3. 사용자가 인증되지 않았기 때문에, ExceptionTranslationFilter는 Start Authentication을 시작합니다. 구성된 AuthenticationEntryPoint는 BasicAuthenticationEntryPoint의 인스턴스로, WWW-Authenticate 헤더를 전송합니다. RequestCache는 일반적으로 NullRequestCache로, 클라이언트가 원래 요청한 요청을 다시 재생할 수 있으므로 요청을 저장하지 않습니다.

클라이언트가 WWW-Authenticate 헤더를 받으면, 사용자 이름과 비밀번호로 다시 시도해야 함을 알게 됩니다. 다음 이미지는 사용자 이름과 비밀번호가 처리되는 흐름을 보여줍니다:

basicauthenticationfilter

앞서 언급된 그림은 우리의 SecurityFilterChain 다이어그램을 기반으로 합니다.

  1. 사용자가 사용자 이름과 비밀번호를 제출할 때, BasicAuthenticationFilter는 HttpServletRequest에서 사용자 이름과 비밀번호를 추출하여 UsernamePasswordAuthenticationToken을 생성합니다. 이는 Authentication의 한 유형입니다.
  2. 다음으로, UsernamePasswordAuthenticationToken은 인증을 위해 AuthenticationManager로 전달됩니다. AuthenticationManager의 구체적인 모습은 사용자 정보가 어떻게 저장되어 있는지에 따라 달라집니다.
  3. 인증에 실패하면, 실패입니다.
    1. SecurityContextHolder가 비워집니다.
    1. RememberMeServices.loginFail이 호출됩니다. 리멤버 미(remember me)가 구성되지 않은 경우, 이는 작업 없음입니다. Javadoc에서 RememberMeServices 인터페이스를 참조하세요.
    1. AuthenticationEntryPoint가 호출되어 WWW-Authenticate가 다시 전송되도록 합니다. Javadoc에서 AuthenticationEntryPoint 인터페이스를 참조하세요. 인증에 성공하면, 성공입니다.
  1. Authentication이 SecurityContextHolder에 설정됩니다.
    1. RememberMeServices.loginSuccess가 호출됩니다. 리멤버 미가 구성되지 않은 경우, 이는 작업 없음입니다. Javadoc에서 RememberMeServices 인터페이스를 참조하세요.
    1. BasicAuthenticationFilter는 FilterChain.doFilter(request,response)를 호출하여 애플리케이션의 나머지 로직으로 계속 진행합니다. Javadoc에서 - 3. BasicAuthenticationFilter 클래스를 참조하세요.

기본적으로, 스프링 시큐리티의 HTTP 기본 인증 지원이 활성화되어 있습니다. 그러나, 서블릿 기반 구성이 제공되는 즉시, HTTP 기본은 명시적으로 제공되어야 합니다.

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
	http
		// ...
		.httpBasic(withDefaults());
	return http.build();
}

추가되는 Filters

  • BasicAuthenticationFilter

httpBasic 설정과 관련있는 객체들

UsernamePasswordMechanism-HttpBasic (2)

⚠️ **GitHub.com Fallback** ⚠️