Spring Security

두주·2024년 1월 17일
0

TIL

목록 보기
33/58

Principal : User의 식별자로, userId, Email과 같은 정보를 담고 있는 객체
Credentials : Password와 같이 중요한 정보로, 유출 방지를 위해 인증된 이후 삭제함
Authorities : 권한 정보로, 보통 Role 혹은 Scope로 설정함

실제로 Authentication 인터페이스를 보면, 구현체를 작성하여 인증 정보를 담는 객체로 사용한다.

setAuthenticated 를 통해 인증 여부를 설정하고, isAtuthenticated 를 통해 인증 여부를 조회한다.

  • JAVA 코드
public interface Authentication extends Principal, Serializable {
	Collection<? extends GrantedAuthority> getAuthorities();

	Object getCredentials();

	Object getDetails();

	Object getPrincipal();

	boolean isAuthenticated(),

	void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentExcept
}
  • Kotlin 변환
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)
  • Authentication 조회
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 객체를 할당하는 것이 핵심이다.

  • AuthenticationManager (interface)
    • Filter로 부터 principal, credentials등의 정보가 담긴 Authentication 객체를 받아 인증을 수행하는 역할을 합니다.

      public interface AuthenticationManager {
      
      	Authentication authenticate(Authentication authentication) throws AuthenticationException;
      
      }
  • ProviderManager
    • AuthenticationManager의 구현체 입니다.
  • AuthenticationProvider
    • Provider에 주입될 수있는 객체로, 각 AuthenticationProvider는 서로 다른 종류의 인증을 수행합니다. 예를들어, email / password기반 로그인을 수행하는 EmailPasswordAuthenticationProvider, JWT에 대한 검증을 수행하는 JwtAuthenticationProvider, 카카오톡 로그인을 수행하는 KakaoAuthenticationProvider 등이 있을 수 있겠죠? AuthenticationProvider 자체도 하나의 인터페이스이기 때문에, 이를 직접 구현해주면 됩니다!
    • 이때, ProviderManager는 AuthenticationProvider의 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);

}
  • 결국 최종적으로 AuthenticationManager(Provider Manager)에서 authenticate() 를 호출하면, AuthenticationProvider 의 authenticate() 가 호출되고, 여기서 인증이 진행됩니다! 이때 Authentication 객체를 확인하여 인증정보를 확인하고, 인증이 되면, Authentication 객체에서 setAuthenticated(true) 를 호출해주고, 중요정보인 credential을 지우는 등의 조작을 수행하여 다시 반환해줍니다!
profile
야옹.

0개의 댓글