Principal : User의 식별자로, userId, Email과 같은 정보를 담고 있는 객체
Credentials : Password와 같이 중요한 정보로, 유출 방지를 위해 인증된 이후 삭제함
Authorities : 권한 정보로, 보통 Role 혹은 Scope로 설정함
실제로 Authentication 인터페이스를 보면, 구현체를 작성하여 인증 정보를 담는 객체로 사용한다.
setAuthenticated 를 통해 인증 여부를 설정하고, isAtuthenticated 를 통해 인증 여부를 조회한다.
public interface Authentication extends Principal, Serializable {
Collection<? extends GrantedAuthority> getAuthorities();
Object getCredentials();
Object getDetails();
Object getPrincipal();
boolean isAuthenticated(),
void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentExcept
}
interface Authentication : Principal, Serializable {
val authorities: Collection<out GrantedAuthority>
val credentials: Any
val details: Any
val principal: Any
val isAuthenticated: Boolean
@Throws(IllegalArgumentException::class)
fun setAuthenticated(isAuthenticated: Boolean)
}
Security Context가 Authentication을 담는 컨테이너고,
Context Holder가 Security Context를 관리한다. 로 볼 수 있다.
실제 설정 내용
Authentication 설정
val context: SecurityContext = SecurityContextHolder.createEmptyContext()
val authentication: Authentication = TestingAuthenticationToken("Username")
context.authentication = authentication
SecurityContextHolder.setContext(context)
val context = SecurityContextHolder.getContext()
val authentication = context.authentication
val username = authentication.principal
val authorities = authentication.authorities
실제로 위와 같은 코드를 작성해서 직전 프로젝트에서 인증을 시도했었다.
override fun signIn(signInRequest: SignInRequest): UserResponse {
val usernamePasswordAuthenticationToken = UsernamePasswordAuthenticationToken(
signInRequest.email,
signInRequest.password
)
try {
val authentication = authenticationManagerBuilder.getObject().authenticate(usernamePasswordAuthenticationToken)
SecurityContextHolder.getContext().authentication = authentication
} catch (e: AuthenticationException) {
log.error("Authentication failed", e)
throw ResponseStatusException(HttpStatus.UNAUTHORIZED, "Authentication failed", e)
}
지금 보니 대충 무슨 의도였는지 알 것 같기도 하고 알쏭달쏭하다.
제대로 공부하고 쓴 코드가 아닌 만큼 뭘 써놨는지 잘 모르겠다.
안됐던게 당연한 걸수도.
인증 필터를 통해 요청받아, 인증 여부를 판단하고, 인증이 됐을 시
SecurityContextHolder에 Authentication 객체를 할당하는 것이 핵심이다.
Filter로 부터 principal, credentials등의 정보가 담긴 Authentication
객체를 받아 인증을 수행하는 역할을 합니다.
public interface AuthenticationManager {
Authentication authenticate(Authentication authentication) throws AuthenticationException;
}
support(authentication: Authentication)
함수를 통해 어떤 Provider를 사용할지 결정합니다. 우리가 여러 방식의 인증을 지원한다면, 실제로 각 인증과정마다 Authentication
객체에 담기는 정보는 다를거에요. 그렇기 때문에, 우리는 인증 과정별로 다른 Authentication
인터페이스의 구현체를 사용할거에요! 일반적으로 우리는 ~~~Token
과 같은 형태로 해당 구현체를 네이밍을 해줍니다. class JwtAuthenticationToken : Authentication
처럼요! 우리는 각 AuthenticationProvider 에서 support 함수를 작성해줌으로써 어떤 Token을 지원하는 인증을 제공하는지 표기해줌으로써, ProviderManager가 인증 Token별로 적절한 AuthenticationProvider를 쓸 수 있게 끔 해줄 수 있습니다. - public interface AuthenticationProvider {
// 실제 인증 수행
Authentication authenticate(Authentication authentication) throws AuthenticationException;
// 어떤 종류의 Authentication 구현체를 통해 인증을 수행하는지 확인
boolean supports(Class<?> authentication);
}