Spring Security
인증 , 권한 부여 및 일반적인 공격에 대한 보호를 제공하는 프레임워크
- 인증(Authentication) : 사용자가 누구인지 확인하는 과정
- 권한 부여(Authorization) : 인증된 사용자가 특정 자원에 접근할 수 있는지 결정하는 과정
- 세션 관리(Session Management) : 사용자 세션을 관리하고, 동시 로그인을 제한할 수 있음
- CORS(Cross-Origin Resource Sharing) : 다른 도메인의 리소스를 안전하게 요청할 수 있도록 하는 매커니즘
- JWT(JSON Web Token) : 사용자의 인증 정보를 JSON 형식으로 표현한 토큰을 사용하여 상태를 유지하지 않는 인증방식을 제공
Spring Security 인증 프로세스
- 인증 필터가 요청을 가로챈다.
- 인증 책임이 인증 관리자에 위임된다.
- 인증 관리자는 인증 논리를 구현하는 인증 공급자를 이용한다.
- 인증 공급자는 사용자 세부 정보 서비스(UserDetailsService)로 사용자를 찾고 암호 인코더(PasswordEncoder)로 암호를 검증한다.
- 인증 결과가 필터에 반환된다.
- 인증된 엔티티에 관한 세부 정보가 보안 컨텍스트에 저장된다.
다음은 SpringBootWebSecurityConfiguration의 내부 코드 중 defaultSecurityFilterChain이다.
Spring Security를 사용하기 위해 build.gradle.kts에 Spring Security 관련 모듈을 추가하면 별도의 처리가 없어도 모든 요청에 대해 인증을 요구하고 기본 로그인 폼이 만들어져 있는 이유가 defaultSecurityFilterChain 메서드 내 다음과 같이 설정되어 있기 때문이다.
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((requests) -> {
((AuthorizeHttpRequestsConfigurer.AuthorizedUrl)requests.anyRequest()).authenticated();
});
http.formLogin(Customizer.withDefaults());
http.httpBasic(Customizer.withDefaults());
return (SecurityFilterChain)http.build();
}
Spring은 기본적으로 Filter Chain을 통해 Controller 앞 단에서 다양한 역할들을 수행한다.
예) 이미지 변환 혹은 데이터 압축, 암호화, 인증, 로깅, 캐싱 등 도메인 로직 외에 부가적으로 필요한 기능들을 수행
Spring은 우리가 넣고 싶은 기능을 추가할 수 있도록 DelegatingFilterProxy를 제공한다.
DelegatingFilterProxy는 Application Context와의 Bridge 역할을 하여, 우리가 작성한 Bean들을 Filter(ServletFilter)에서 사용할 수 있게 해준다.
Spring Security는 DelegatingFilterProxy에 FilterChainProxy를 제공하여 인증과 관련된 FilterChain을 적용할 수 있게 해준다.
요청에 따라 서로 다른 FilterChain이 적용되게 할 수 있는 기능도 적용할 수 있다.
예) URL별로 인증 혹은 인가에 대해 다르게 처리해야할 때
Spring Security의 인증 처리 과정
- Authentication: 인증 정보를 담고 있는 객체로 이를 통해 인증 여부를 확인
- Principal: User의 식별자, User Id, Email과 같은 정보를 담고 있는 객체
- Credentials: Password와 같은 중요한 정보로, 유출방지를 위해 인증된 이후 삭제됨
- Authorities: 권한 정보, Role 또는 Scope로 설정
SecurityContextHolder는 SecurityContext를 관리하는 역할을 하고 SecurityContext는 Authentication 객체를 담는 Container 역할을 한다.
Authentication 인터페이스는 다음과 같고 이 인터페이스의 구현체를 작성하여 인증 정보를 담는 객체로 사용한다.
public interface Authentication extends Principal, Serializable {
Collection<? extends GrantedAuthority> getAuthorities(); // 사용자의 권한(Role)을 반환
Object getCredentials(); // 사용자 인증에 사용되는 자격 증명을 반환(예: 비밀번호)
Object getDetails(); // 인증에 대한 추가 세부 정보를 반환
Object getPrincipal(); // 인증된 주체를 반환(예: 사용자)
boolean isAuthenticated(); // 현재 사용자가 인증되었는지 여부를 반환
void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException; // 사용자의 인증 상태 설정
}
인증 과정의 핵심은 인증 필터를 통해 요청을 받아 인증 여부를 판단하고 인증 됐을 시 SecurityContextHolder에 Authentication 객체를 할당하는 것이 핵심이다.
인증을 담당하는 Filter 객체를 직접 작성하거나 Spring Security에서 제공하는 Filter들을 이용하여 Spring Security에 등록해주면 인증을 처리할 수 있다.
Spring Security는 인증 처리를 위한 다양한 요소들을 제공한다.
Filter에서 Authentication 객체를 바로 다뤄 인증을 처리하기 보다 HTTP 요청으로부터 받은 정보를 Authentication 객체에 담아준 후 실제 인증을 위한 처리는 Filter가 아닌 다른 객체들이 담당 하도록 하는데 이런 역할을 하는 대표적인 요소들은 다음과 같다.
- AuthticationManager(interface) : Filter로부터 principal, credentials 등의 정보가 담긴 Authentication 객체를 받아 인증을 수행하는 역할을 한다.
- ProviderManager
- AuthenticationManager의 구현체
- AuthenticationProvider의 support(authentication: Authentication) 함수를 통해 어떤 Provider를 사용할지 결정
- AuthenticationProvider: Provider에 주입될 수 있는 객체로 각 AuthenticationProvider는 서로 다른 종류의 인증을 수행
- EmailPasswordAuthenticationProvider
- JwtAuthenticationProvider
여러 인증 방식을 지원한다면, 각 인증 과정마다 Authentication 객체에 담기는 다른 정보들을 처리하기 위해 인증 과정 별 Authentication 인터페이스의 구현체를 만든다.
각 AuthenticationProvider에서 support 함수를 작성, 어떤 Token을 지원하는 인증을 제공하는지 표기해 ProviderManager가 인증 Token별로 적절한 AuthenticationProvider를 쓸 수 있게 해줄 수 있다.
최종적으로 AuthenticationManager(Provider Manager)에서 authentication()를 호출하면 AuthenticationProvider의 authenticate()가 호출되고 인증이 진행된다.
Authentication 객체를 확인해 인증 정보를 확인하고 인증이 되면 Authentication 객체에서 setAuthentication(true)를 호출해주고 중요 정보인 credential을 지우는 등의 수행 후 다시 반환한다.
Authentication 객체를 확인하여 인증이 됐을 시 SecurityContextHolder에 Authentication 객체를 설정해준다.
'TIL(Today I Learned)' 카테고리의 다른 글
TIL - 비밀번호 수정 요청 시 기존 비밀번호를 사용하지 못하게 하기 (0) | 2024.06.13 |
---|---|
TIL - Spring Security Filter (0) | 2024.06.12 |
TIL - Kotest 테스트 코드 작성하기 (0) | 2024.06.10 |
TIL - 서버에서 보낸 쿠키가 브라우저에 저장되지 않는 문제 (0) | 2024.06.07 |
TIL - React에서 useState를 사용할 때 호출이 여러 번 발생 (0) | 2024.06.05 |