[개인 프로젝트] Spring Security Form Login

Turtle·2024년 8월 30일
0

👉문제 상황

Spring Security에서 제공하는 폼 로그인에 대한 이해가 부족해서 문제가 발생한 것 같다.

사용자가 이메일과 패스워드를 입력하면 Spring Security가 HTTP 요청을 가로채 login 요청을 처리하게 되는데 이 과정을 정리해두고자 한다.

♻️HTML 폼 처리 코드 부분

<form th:action="@{/login}" method="post">
	<div class="form-group">
    <label for="email">이메일</label>
    	<input type="text" id="email" name="email" class="form-control" placeholder="이메일을 입력하세요" required></div>
  	<div class="form-group">
    <label for="password">비밀번호</label>
    	<input type="password" id="password" name="password" class="form-control" placeholder="패스워드를 입력하세요" required></div>
	<button type="submit" class="btn btn-primary btn-block">로그인</button>
</form>

👉왜 Spring Security 폼 로그인이 안됐던 걸까?

  • 현재 폼에서 넘겨주는 값은 email, password다. 근데 이 email이 문제였던 것이다.
  • 그러나 아래 FormLoginConfigurer 코드를 보면 기본적으로 usernameParameter은 username이고 passwordParameter은 password이다.
  • 나의 프로젝트에서는 이메일을 아이디로 사용하기에 바꿔줘야했다.
public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractAuthenticationFilterConfigurer<H, FormLoginConfigurer<H>, UsernamePasswordAuthenticationFilter> {
    public FormLoginConfigurer() {
        super(new UsernamePasswordAuthenticationFilter(), (String)null);
        this.usernameParameter("username");
        this.passwordParameter("password");
    }
    
    // ...

♻️개선된 SpringSecurity 코드

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
	RequestCache nullRequestCache = new NullRequestCache();

	http.cors(Customizer.withDefaults())
    	.csrf(AbstractHttpConfigurer::disable);
    http.authorizeHttpRequests(
		auth -> auth
		.requestMatchers(
			new AntPathRequestMatcher("/js/**"),			
            new AntPathRequestMatcher("/img/**"),			
			new AntPathRequestMatcher("/css/**"),			
            new AntPathRequestMatcher("/auth/login"),		
			new AntPathRequestMatcher("/auth/signup"),		
			new AntPathRequestMatcher("/login"),			
			new AntPathRequestMatcher("/signup"),			
			new AntPathRequestMatcher("/"))				
		.permitAll().anyRequest().authenticated())
		.formLogin(formLogin -> formLogin.loginPage("/auth/login")
				.usernameParameter("email")
				.loginProcessingUrl("/login")
				.permitAll()
		.defaultSuccessUrl("/board/posts"))
		.logout(logout -> logout.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
		.logoutSuccessUrl("/auth/login")
		.invalidateHttpSession(true))
		.oauth2Login(oauth -> oauth.userInfoEndpoint(
				oauthService -> oauthService.userService(principalOauthDetailsService))
		.defaultSuccessUrl("/board/posts"))
		.requestCache((cache) -> cache.requestCache(nullRequestCache));
	return http.build();
}

♻️Spring Security Form Login

  • Spring Security는 HTML 폼을 통해 제공되는 사용자 이름과 비밀번호에 대한 지원을 제공한다.

👉과정 정리

  • 사용자는 인가되지않은 리소스에 대해 비인증 요청을 보낸다.
  • Spring Security 인증 필터는 AccessDeniedException을 발생시켜 인증되지 않은 요청이 거부되었음을 알린다.
  • 사용자가 인증이 되지 않았으므로 ExceptionTranslationFilter가 인증 과정을 시작하도록 하면서 AuthenticationEntryPoint를 사용하여 로그인 페이지로 리다이렉션한다. AuthenticationEntryPointLoginUrlAuthenticationEntryPoint의 인스턴스이다.
  • 브라우저는 리디렉션된 로그인 페이지로 요청을 보낸다.
  • 로그인 페이지가 렌더링된다.

👉과정 정리

  • 사용자가 사용자 이름과 패스워드를 제출하면 UsernamePasswordAuthenticationFilterHttpServletRequest 인스턴스에서 사용자 이름과 패스워드를 추출하여 인증 유형인 UsernamePasswordAuthenticationToken을 생성한다.
  • UsernamePasswordAuthenticationTokenAuthenticationManager 인스턴스에 전달하여 인증한다.
    • failure) 만약 인증에 실패하면 SecurityContextHolder가 비워진다.
    • success) 만약 인증에 성공하면 SecurityContextHolder에 인증 정보가 설정된다. 그리고 나서 AuthenticationSuccessHandler가 호출된다. 커스텀으로도 구성이 가능하다.

0개의 댓글