UsernamePasswordAuthenticationFilter를 통한 인증과정

방세현·2023년 4월 11일
0

spring security

목록 보기
1/2

전체적인 흐름


  1. 클라이언트로 요청을 받으면 요청된 인증을 UsernamePasswordAuthenticationFiler(위 그림에선 AuthenticationFilter)에서 처리한다.

  2. 요청된 인증을 처리한 후 HttpServletRequest객체로 UsernamePasswordAuthenticationToken에 전달한다.
    2.1 UsernamePasswordAuthentication에서 username과 password를 추출해서 Authentication 객체를 생성한다.(setAuthenticated = false).

  3. 생성된 Authentication 객체를 AuthManager 인터페이스를 구현하고 있는 ProviderManager의 Authentication authentication(Authentication authentication)로 넘긴다.

  4. 이 메소드는 for문을 돌면서 AuthenticationProvider의 provider, 즉 각 provider가 인증을 할 수 있는지 여부를 확인합니다. 모든 provider 중에서 해당 인증을 처리할 수 있는 provider를 찾아 (supports메소드가 true) 실제 인증 절차인 authenticate() 메서드를 실행시킵니다

ProviderManager.java

@Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		Class<? extends Authentication> toTest = authentication.getClass();
		AuthenticationException lastException = null;
		AuthenticationException parentException = null;
		Authentication result = null;
		Authentication parentResult = null;
		int currentPosition = 0;
		int size = this.providers.size();
		for (AuthenticationProvider provider : getProviders()) {
			if (!provider.supports(toTest)) {	//인증 가능한지 체크
				continue;
			}
			if (logger.isTraceEnabled()) {
				logger.trace(LogMessage.format("Authenticating request with %s (%d/%d)",
						provider.getClass().getSimpleName(), ++currentPosition, size));
			}
			try {
				result = provider.authenticate(authentication);	//인증이 가능하면 여기서 인증
				if (result != null) {
					copyDetails(authentication, result);
					break;
				}
			}
			catch (AccountStatusException | InternalAuthenticationServiceException ex) {
				prepareException(ex, authentication);
				// SEC-546: Avoid polling additional providers if auth failure is due to
				// invalid account status
				throw ex;
			}
			catch (AuthenticationException ex) {
				lastException = ex;
			}

참고로 AuthenticationProvider 인터페이스를 구현한 클래스 이름은 AbstractUserDetailsAuthenticationProvider이다.

  1. 인증이 가능하면 AbstractUserDetailsAuthenticationProvider클래스의 authenticate()를 실행 시킨다. authentication()에 있는 DaoAuthenticationProvider.retreiveUser()가 실행된다. 이 메서드의 try부분을 통해 UserDetails을 받아온다.

그후 다시 AbstractUserDetailsAuthenticationProvider.authenticate()의 additionalAuthenticationChecks()를 통해 해당 유저의 비밀번호 일치 여부를 체크한다. 이 메서드 또한 DaoAuthenticationProvider클래스에 구현되어있다. additionalAuthenticationChecks()는 비밀번호가 일치하는지 여부를 확인하는 메서드이다.

DaoAuthenticationProvider
@Override
    protected final UserDetails as(String username, UsernamePasswordAuthenticationToken authentication)
            throws AuthenticationException {
        prepareTimingAttackProtection();
        try{
            UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username); //UserDetails 호출
            //생략
        }
    }

이렇게 비밀번호까지 확인했다면 AbstractUserDetailsAuthenticationProvider 클래스의 authenticate()는 createSuccessAuthentication()메서드를 리턴합니다.

protected Authentication createSuccessAuthentication(Object principal, Authentication authentication, UserDetails user){
	UsernamePasswordAuthenticationToken result = new
    UsernamePasswordAuthenticationToken(principal,
				authentication.getCredentials(),
                this.authoritiesMapper.mapAuthorities(user.getAuthorities()));
	result.setDetails(authentication.getDetails());
	this.logger.debug("Authenticated user");
	return result;
}

이때 authenticated 값은 true 가 되고 해당 객체는 인증 완료된 Authentication 객체가 만들어진다.
10. 검증된 토큰을 SecurityContextHolder안에 있는 SecurityContext에 저장한다. (아래 Authentication객체의 인증 후 참고)


SecurityContextHolder


인증된 사용자의 상세 정보를 보관해주는 장소(Authentication을 담고있는 곳)


SecurityContext


인증된 사용자의 정보(Authentication)를 가짐


Authentication


  • 인증 전 : 인증을 요구하는 주체가 인증에 필요한 정보 (ID, PW)를 제공하기 위해 사용
    • principal: 로그인 시도 아이디 (String)
    • credentials : 로그인 시도 비밀번호(String)
    • authorities : x
  • 인증 후 : 인증이 완료된 사용자의 정보를 저장하는데 사용
    • principal : 인증이 완료된 사용자 객체(UserDetails)
    • credentials : 인증 완료 후 유출 가능성을 줄이기 위해 삭제(null이나 빈값등)
    • authorities : 인증된 사용자가 가지는 권한 목록, isAuthenticated() = true

UserDetails


String Security에 사용자의 정보를 담는 인터페이스


UserDetailsService


Spring Security에서 사용자의 정보를 가져오는 인터페이스

메소드리턴타입설명
loadUserByUsernameUserDetails유저의 정보를 불러와서 UserDetails로 리턴

AuthenticationManager


authentication 객체의 인증을 처리 후 다시 authentication 객체를 돌려주는 인터페이스
이를 통해 인증되면 isAuthenticated(boolean)의 값을 TRUE로 바꿔준다.


ProviderManager

AuthenticationManager 인터페이스의 구현체
인증을 AuthenticationProvider들에게 위임하고 그 중 하나의 AuthenticationProvider 구현 클래스가 인증에 성공하면

AuthenticationProvider


아이디와 비밀번호가 유효한지 검사

0개의 댓글