
↓ Servlet Authentication Architecture

FormLogin 방식에 대해서 구글링을 하다보면 위에서 본 아키텍처에서 UsernamePasswordAuthenticationToken은 빠질 수 없는 주제임.FormLogin 방식을 디버깅을 통해 내부 구조를 간략하게 살펴보고 기록해놓기.UsernamePasswordAuthenticationToken에 브레이크 포인트를 걸어놓고 디버깅.↓UsernamePasswordAuthenticationFilter에서 UsernamePasswordAuthenticationToken의 unauthenticated()메서드가 가장 먼저 호출되고 UsernamePasswordAuthenticationToken의 생성자를 호출함.
principal, credentials 멤버필드에 값이 할당됨.
↓ 반환값은 UsernamePasswordAuthenticationToken타입의 authRequest에 저장.DEAFULT_ANT_PATH_REQUEST_MATCHER가 있는데 "/login", (httpMethod)"POST"를 확인할 수 있음.

↓ authRequest를 보면 아이디, 비밀번호만 할당되어 있는 상황.
↓ this.setDetails()메서드를 통해 세션id를 할당 받은 모습.
this.getAuthenticationManager().authenticate()에 authRequest를 담아서 호출.↓ 그러면 UserDetails의 구현체에 오버라이딩 되어있는 getAuthorities()가 호출됨.
↓ 그 다음 AbstractUserDetailsAuthenticationProvider의 createSuccessAuthentication()메서드가 호출되고 이 메서드의 매개변수에 할당된 값은 아래와 같음.
↓ 메서드 내부에서 UsernamePasswordAuthenticationToken의 authenticated()메서드가 호출됨.UsernamePasswordAuthenticationToken.authenticated(principal, authentication.getCredentials(), this.authoritiesMapper.mapAuthorities(user.getAuthorities()));
unauthenticated()메서드에 아이디, 비밀번호만 사용됐지만authenticated()메서드에 아이디, 비밀번호, Collection 타입의 권한까지 받고 있는 모습.super()를 호출하면서 null을 전달했지만super()를 통해 Collection 타입의 권한을 전달해줌.this.setAuthenticated(true)를 호출함.

public abstract class AbstractAuthenticationToken implements Authentication, CredentialsContainer {
private final Collection<GrantedAuthority> authorities;
private Object details;
private boolean authenticated = false;
public AbstractAuthenticationToken(Collection<? extends GrantedAuthority> authorities) {
if (authorities == null) {
this.authorities = AuthorityUtils.NO_AUTHORITIES;
} else {
Iterator var2 = authorities.iterator();
while(var2.hasNext()) {
GrantedAuthority a = (GrantedAuthority)var2.next();
Assert.notNull(a, "Authorities collection cannot contain any null elements");
}
this.authorities = Collections.unmodifiableList(new ArrayList(authorities));
}
}
public Collection<GrantedAuthority> getAuthorities() {
return this.authorities;
}
public String getName() {
Object var2 = this.getPrincipal();
if (var2 instanceof UserDetails userDetails) {
return userDetails.getUsername();
} else {
var2 = this.getPrincipal();
if (var2 instanceof AuthenticatedPrincipal authenticatedPrincipal) {
return authenticatedPrincipal.getName();
} else {
var2 = this.getPrincipal();
if (var2 instanceof Principal principal) {
return principal.getName();
} else {
return this.getPrincipal() == null ? "" : this.getPrincipal().toString();
}
}
}
}
public boolean isAuthenticated() {
return this.authenticated;
}
public void setAuthenticated(boolean authenticated) {
this.authenticated = authenticated;
}
....
}
logger.debug("Authenticated user")를 출력하고 result(UsernamePasswordAuthenticationToken 타입)을 리턴함.
Principal을 넣어놓고 디버깅.
principal, siteUser(User 엔터티)), 권한(authorities), details(세션id), authenticated(=true)가 들어있음.