본문 바로가기
Back-End/Spring Security

Spring Security Authentication (1) Form-Login

by sharekim 2021. 3. 16.

Spring Security에서는 기본적으로 Form-Login을 제공하고 있다. 

아래는 로그인 페이지에 접근하는 과정이다.

 

Redirecting to the Log In Page

1. First, a user makes an unauthenticated request to the resource /private for which it is not authorized.

가장 먼저 유저는 비인가된 리퀘스트를 /private 로 요청한다.

 

2. Spring Security’s FilterSecurityInterceptor indicates that the unauthenticated request is Denied by throwing an AccessDeniedException.

스프링 시큐리티의 FilterSecurityInterceptor 가 비인가된 요청을 AccessDeniedException 을 던지며 접근을 거부한다.

 

3. Since the user is not authenticated, ExceptionTranslationFilter initiates Start Authentication and sends a redirect to the log in page with the configured AuthenticationEntryPoint.

유저가 비인가되었기 때문에 ExceptionTranslationFilter 가 시작되고, AuthenticationEntryPoint가 설정된 Login페이지로 Redirect 한다. 

 

4. The browser will then request the log in page that it was redirected to.

브라우저는 Redirect된 로그인페이지를 요청한다.

 

5. Something within the application, must render the log in page.

로그인페이지가 렌더링 된다.

 

 

로그인 페이지에 접근하고 유저가 username과 password를 submit 하게 되면 아래와 같이 작동한다.

 

Authenticating Username and Password

 

1. When the user submits their username and password, the UsernamePasswordAuthenticationFilter creates a UsernamePasswordAuthenticationToken which is a type of Authentication by extracting the username and password from the HttpServletRequest.

유저가 username과 password를 submit 하게 되면 UsernamePasswordAuthenticationFilter 가 UsernamePasswordAuthenticationToken 를 생성한다.

 

2. Next, the UsernamePasswordAuthenticationToken is passed into the AuthenticationManager to be authenticated. 

UsernamePasswordAuthenticationTokenAuthenticationManager에게 전달되고 인증된다. 

 

3. If authentication fails, then Failure
인증 실패 시

  • The SecurityContextHolder is cleared out.
    SecurityContextHolder는 지워지고
  • RememberMeServices.loginFail is invoked. If remember me is not configured, this is a no-op.
    RememberMeServices.loginFail 이 실행된다. remember me 가 설정되지 않은 경우 no-op이다.
  • AuthenticationFailureHandler is invoked.
    AuthenticationFailureHandler가 실행된다.

4. If authentication is successful, then Success.
인증 성공 시

  • SessionAuthenticationStrategy is notified of a new log in.
    SessionAuthenticationStrategy 가 새로운 로그인에 대해 알림을 받는다.
  • The Authentication is set on the SecurityContextHolder.
    SecurityContextHolder에 인증이 설정된다.
  • RememberMeServices.loginSuccess is invoked. If remember me is not configured, this is a no-op.
    RememberMeServices.loginFail 이 실행된다. remember me 가 설정되지 않은 경우 no-op이다.
  • ApplicationEventPublisher publishes an InteractiveAuthenticationSuccessEvent.
    ApplicationEventPublisher 가 InteractiveAuthenticationSuccessEvent를 발행한다.
  • The AuthenticationSuccessHandler is invoked. Typically this is a SimpleUrlAuthenticationSuccessHandler which will redirect to a request saved by ExceptionTranslationFilter when we redirect to the log in page.
    AuthenticationSuccessHandler 가 실행된다. 보통 SimpleUrlAuthenticationSuccessHandler 이며, ExceptionTranslationFilter가 Redirect 하기 전의 페이지로 이동시킨다.

여기서 약간 Spring Boot로 Security를 구현해야 하나 하는 고민이 들게 하는 부분이 있는데

 

SpringBoot 버전

protected void configure(HttpSecurity http) {
    http
        // ...
        .formLogin(withDefaults());
}

Spring MVC 버전

1) 컨트롤러 구현

@Controller
class LoginController {
    @GetMapping("/login")
    String login() {
        return "login";
    }
}

2) 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 생성 시 유의점

1. 반드시 post 방식이어야 하며 Servlet Context는 /login 이어야 한다.

2. 반드시 Thymeleaf 에 자동으로 포함된 CSRF토큰이 필요하다.

3. username을 username이라는 파라미터로 지정해야 한다.

4. password를 password라는 파라미터로 지정해야 한다.

5. 파라미터 오류가 발생한 경우, 유저가 유요한 username 또는 password를 제공하지 않은 것이다.

6. HTTP parameter logout이 발견된 경우, 정상적으로 로그아웃 된 것이다.

 

 

위와 같이 두 가지를 셋팅해주어야 하고 Thymeleaf 또한 사용해주어야 한다.

 

#Basic Authentication

위에서 설명한 Form Login과 비슷하고 보다 단순화된 구조로 진행된다. 그림으로만 이해하도록 하자.

Sending WWW-Authenticate Header
Authenticating Username and Password

 

다른 방식으로는 Digest Authentication, In-Memory Authentication, JDBC Authentication 등이 있는데

Digest Authentication는 문서에 사용하지 말라고 되어 있고

In-Memory Authentication 은 메모리에 등록해서(Bean으로 셋팅해서) 사용하는 방법이라 예시가 아닌 한 사용하지 않을 것 같다.

 

다음 포스팅에서 JDBC Authentication를 공부해보겠다.

 

 

 

 

*모든 이미지와 자료 출처는 Spring.io입니다.