AuthenticationMnager에 대해

어떠한 Web Application에서 Spring Security사용하여 로그인을 Form Login 방식으로 구현했다면

해당 Application의 로그인 요청을 일반적으로 UsernamePasswordAuthenticationFilter라는 필터에 의해 처리된다.

 

사용자가 로그인폼에서 작성한 아이디와 비밀번호를 제출하면, 해당 formData를 HTTP 요청과 함께 서버로 전송하는데

Spring Security는 Servlet Filter 기반의 보안체인들을 사용하기 때문에, 이러한 요청들이 여러가지 보안 관련 필터들을 거쳐오게 된다.

 

그 많은 필터들 중 UsernamePasswordAuthenticationFilter는 POST 방식으로 들어온 로그인 요청을 처리하는 역할을 하는데 아래와 같은 작업들을 수행한다.

 

  1. HTTP 요청으로부터 사용자 이름과 비밀번호를 추출
  2. 이 정보를 바탕으로 UsernamePasswordAuthenticationToken 객체를 생성
  3. 생성한 토큰을 AuthenticationManager에게 전달하여 인증 절차를 진행
  4. 인증 성공 시 AuthenticationSuccessHandler 호출, 실패하면 AuthenticationFailureHandler를 호출

 

그래서 AuthenticationMnager란?

 AuthenticationManager는 Spring Security에서 인증을 담당하는 핵심 인터페이스이다.

 

이 인터페이스의 핵심 역할은 Authentication 객체를 사용하여 인증을 시도하고, 인증이 성공하면 권한정보까지 포함된

Authentication 객체를 반환한다. 

 

AuthenticationManager는 여러가지의 구현체가 존재하는데 그 중 Security에서 가장 기본적으로 제공하는 구현체는ProviderManager 클래스이다.

 

이때 비슷한 명칭때문에 헷갈릴 수 있는 인터페이스가 하나있는데 바로 AuthenticationProvider이다.

AuthenticationProvider는 실제 인증 로직을 담당하는 인터페이스로서 아래와 같이 개발자가 상속받아 구현하여 인증 로직을 커스터마이징할 수 있다.

 

package com.example.happyusf.Security;

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Component;


@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
    // 보통 AuthenticationProvider는 상태를 가지지 않는 클래스이므로, 생성자 주입을 사용하여 필요한 의존성들을 주입하도록 한다.
    private final UserDetailsService userDetailsService;
    private final BCryptPasswordEncoder passwordEncoder;


    public CustomAuthenticationProvider(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
        this.passwordEncoder = new BCryptPasswordEncoder();
    }
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = authentication.getName();
        String password = (String) authentication.getCredentials();

        UserDetails loadedUser = userDetailsService.loadUserByUsername(username);

        if (loadedUser == null) {
            throw new BadCredentialsException("존재하지 않는 ID입니다.");
        }else if(!password.equals(loadedUser.getPassword())){
            throw new BadCredentialsException("패스워드가 일치하지 않습니다.");
        }


        return new UsernamePasswordAuthenticationToken(loadedUser, password, loadedUser.getAuthorities());
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return UsernamePasswordAuthenticationToken.class.isAssignableFrom(aClass);
    }
}

 

 

반면 ProviderManager(org.springframework.security.authentication.ProviderManager)는

여러개의 AuthenticationProvider 관리하는 역할을 하는 AuthenticationManager 구현체이다.