스택을 보면
FilterChainProxy -> do.Filter() -> (이동)해당필터.doFilter() -> 요청 ~~ 이동 쭉쭉 이어간다
이때
FilterChainProxy 클래스에서 nextFilter.doFilter() 가 실행되는데 이때 nextFilter는
additionalFilters에 담겨있는 N개의 필터중 currentPostition 순번째의 필터를 의미한다. 즉
currentPosition 이 addtitionalFilters.size() 와 동일할때 까지 등록되어 있는 SecurityFilterChain 이 다돌아갈떄 까지 진행된다고 생각하면된다.
UsernamePasswordAuthenticationFilter.doFilter() 를 요청했는데
UsernamePasswordAuthenticationFilter 는 (AbstractAuthenticationProcessingFilter)를 상속하였으므로 AbstractAuthenticationProcessingFilter.doFiliter()가 실행되고, 해당 doFilter()안에서
- attemptAuthentication(request, response) 메서드가 실행되었고, 해당 attemptAuthentication(request, response) 는
- UsernamePasswordAuthenticationFilter 에서 재정의하고 있으므로 UsernamePasswordAuthenticationFilter 에서 실
행된다.
<UsernamePasswordAuthenticationFilter> - attemptAuthentication()
해당 필터에서 UsernamePasswordAuthenticationToken을 만들어서
UsernamePasswordAuthenticationToken 의 Details에 주입하고 있다.
-> Token생성 후 SetDetails(token) 토큰 주입
return 값은 AuthenticationManager 의 authentication() 메서드를 실행하면서 생성한 Token을 주입하고 있다.
AbstractAuthenticationProcessingFilter <- UsernamePasswordAuthenticationFilter
UsernamePasswordAuthenticationFilter 의 부모인 AbstractAuthenticationProcessingFilter 에 정의 되어있다.
즉 AuthenticationManager의 authenticate(Authentication authentication) 를 실행하는것인데
AuthenticationManager 는 Interface로써, AuthenticationManager 를 구현하고 있는 ProviderManager가 실행된다.
ProviderManager.Authentication(Authentication auth)
코드는 아애와 같다.
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
Class<? extends Authentication> toTest = authentication.getClass();
AuthenticationException lastException = null;
Authentication result = null;
boolean debug = logger.isDebugEnabled();
for (AuthenticationProvider provider : getProviders()) {
if (!provider.supports(toTest)) {
continue;
}
if (debug) {
logger.debug("Authentication attempt using "
+ provider.getClass().getName());
}
try {
result = provider.authenticate(authentication);
if (result != null) {
copyDetails(authentication, result);
break;
}
}
catch (AccountStatusException e) {
prepareException(e, authentication);
// SEC-546: Avoid polling additional providers if auth failure is due to
// invalid account status
throw e;
}
catch (InternalAuthenticationServiceException e) {
prepareException(e, authentication);
throw e;
}
catch (AuthenticationException e) {
lastException = e;
}
}
if (result == null && parent != null) {
// Allow the parent to try.
try {
result = parent.authenticate(authentication);
}
catch (ProviderNotFoundException e) {
// ignore as we will throw below if no other exception occurred prior to
// calling parent and the parent
// may throw ProviderNotFound even though a provider in the child already
// handled the request
}
catch (AuthenticationException e) {
lastException = e;
}
}
if (result != null) {
if (eraseCredentialsAfterAuthentication
&& (result instanceof CredentialsContainer)) {
// Authentication is complete. Remove credentials and other secret data
// from authentication
((CredentialsContainer) result).eraseCredentials();
}
eventPublisher.publishAuthenticationSuccess(result);
return result;
}
// Parent was null, or didn't authenticate (or throw an exception).
if (lastException == null) {
lastException = new ProviderNotFoundException(messages.getMessage(
"ProviderManager.providerNotFound",
new Object[] { toTest.getName() },
"No AuthenticationProvider found for {0}"));
}
prepareException(lastException, authentication);
throw lastException;
}
해당 코드를 실행하면서
-- result = parent.authenticate(authentication) 에서 provider.aithenticate() 코드로 이동되는데 이때
-- provider는
-- for( AuthenticationProvide provider : getProviders()){} 매서드를 통해서 얻은것중 하나로
-- 사용자 정의 DB를 통해서 권한을 얻을때 사용되는 AuthenticationProvider로는 DaoAuthenticationProvider 이다.
-- DaoAuthenticationProvider는 AbstractUserDetailsAuthenticationProvider를 상속한다.
따라서 DaoAuthenticationProvider.authentication(authentication) 의경우는 부모의 클래스에서 정의된.
- AbstractUserDetailsAuthenticationProvider.authentication() 이 실행되고 해당 메서드 안에서
- 정의된 retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication); 를 통해서 로그인을 시도한 사람의 UserDetails를 얻어서 user 의 정보를 얻게 된다.
- 그후 코드를 쭉 따라서 아래로 이동하면 createSuccessAuthentication() 매서드를 통해서
- 사용자의 UsernamePasswordAuthenticationToken이 생성되고, 해당 값을 return 해주는것을 알수있다.
* UsernamePasswordAuthenticationToken -> AbstractAuthenticationToken -> Authentication
위의 상속과정을 따르므로 UsernamePasswordAuthenticationToken을 리턴해도 Authentication으로 받을수 있다.
이렇게 Authentication이 리턴되면
SecurityContext에 Authentication 저장 후 인증 완료 처리하면서 로그인이 성공합니다.
============================================================================================
'dev > Spring-security' 카테고리의 다른 글
[Spring] Spring-security를 JSP에서 사용하기 (0) | 2022.08.20 |
---|---|
[Spring] Filter (0) | 2022.08.20 |
[Spring] Spring Security 대략적인 흐름 (0) | 2022.08.06 |
[Spring] spring security 중간정리 (0) | 2022.08.06 |
[Spring] UserDetailsService 활용 (0) | 2022.08.05 |