Structure
일단 인증관련 전체적인 구조는 다음과 같다.
1. 필터를 통해 들어온 요청이 아직 인증되지 않은 것이라면
2. 인증을 시작한다.
3. 또는 요청이 AccessDeniedException이라면 접근을 거부한다.
인증 과정을 살펴보자
SecurityContextHolder
사용자 정보인 principal을 Authentication에서 관리하고
Authentication은 SecurityContext가 관리하고
SecurityContext는 SecurityContextHolder가 관리한다.
SecurityContextHolder의 주요한 역할은 SecurityContext를 스레드와 연결시켜서 Authentication을 저장하도록 하는것이다.
SecurityContextHolder의 ThreadLocal을 사용하므로 스레드가 달라지면 제대로 된 인증 정보를 가져올 수 없다. 따라서 스레드에 맞게 연결방법이 달라야한다.
런타임 시점에 스레드에 맞는 전략(어떻게 연결시킬지)을 주는 제공하는 인터페이스다.
SecurityContextHolderStrategy
3가지 구현체들. 스레드에 따라 얘네중 하나를 쓰는 것.
- GlobalSecurityContextHolderStrategy
application의 모든 스레드에 SecurityContext를 공유
- InheritableThreadLocalSecurityContextHolderStretegy
현재 스레드에서 하위로 생성된 스레드에 SecurityContext를 공유
- ThreadLocalSecurityContextHolderStretegy
현재 스레드에서만 사용가능한 기본 모드
SecurityContext
현재 실행중인 스레드와 관련된 최소한의 정보를 정의하는 인터페이스이다.
구현체는 SecurityContextImpl 하나가 있는데, Authentication을 가지고 있다.
Authentication
Authentication에 대한 토큰을 표현한 것이다.
Authentication 정보는 인증 요청 또는 인증된 principal(AuthenticationManager가 처리해서 인증된)
이다.
일단 요청이 인증이 되면 Authentication은 SecurityContext에 저장된다. 그리고 SecurityContext를
SecurityContextHolder가 관리한다.
UsernamePasswordAuthenticationToken
Authentication의 구현체이다.
User의 ID가 Principal 역할을 하고, Password가 Credential의 역할을 한다. UsernamePasswordAuthenticationToken의 첫 번째 생성자는 인증 전의 객체를 생성하고, 두번째 생성자는 인증이 완료된 객체를 생성한다.
UserDetail
인증에 성공하여 생성된 UserDetail 객체는 usernamePasswordAuthenticationToken을 리턴할 때 사용된다.
public Authentication getAuthentication(String jwt){
UserDetails userDetails
= this.memberService.loadUserByUsername(this.getUsername(jwt));
return new UsernamePasswordAuthenticationToken(
userDetails,"",userDetails.getAuthorities());
}
getAuthorities
GrantAuthority는 현재 사용자(principal)가 가지고 있는 권한을 의미한다.
ROLE_ADMIN나 ROLE_USER와 같이 ROLE_의 형태로 사용하며, 보통 "roles" 이라고 한다.
GrantedAuthority 객체는 UserDetailsService에 의해 불러올 수 있고, 특정 자원에 대한 권한이 있는지를 검사하여 접근 허용 여부를 결정한다.
AuthenticationManager
스프링 시큐리티의 필터가 수행하는 방식을 정의하는 인터페이스이다.
SecurityContextHolder에 Authentication을 누가 설정해 줄까.
그것은 바로 AuthenticationManager를 호출한 Filter가 해준다.
인증 요청된 정보는 필터를 거치고 필터는 해당 요청에 있는 인증 정보를 가지고 Authentication 객체로 만든뒤
AuthenticationManager에게 인증 처리를 맡긴다. 인증되지 않은 정보를 받아서 인증된 정보를 반환한다.
ProviderManager
가장 많이 사용하는 AuthenticationManager의 구현체이다.
ProviderManager는 AuthenticationProvider List에게 인증 처리를 맡긴다.
많은 AuthenticationProviders 는 ProviderManager에 주입할 수 있다.
각각의 AuthenticationProvider는 각각의 인증 방법이 있다.
ex)
DaoAuthenticationProvider 는 이름/비번 기반 인증
JwtAuthenticationProvider는 JWT 토큰 인증을 한다.
왜 굳이 Authentication Provider가 여러개여야하는거지..
여러 인증 로직이 필요할때 Authentication Provider가 여러 개 있어야한다.
첫 번째 Provider에서 인증에 실패하면 다음 Provider의 인증 로직을 진행해야하기 때문에.
참고 내용
예를 들어 A 사에서 SHA256 해시 알고리즘으로 비밀번호 암호화를 진행했습니다. 그런데 레인보우 테이블 공격에 의해 해당 방법이 취약함을 깨달았고, 특정 시점 이후에 가입된 사용자들에는 Bcrypto 방식으로 암호화를 진행했다고 가정하겠습니다.
이러한 경우에 DB 테이블에는 2가지 암호화 방식으로 저장된 비밀번호가 섞여있고, 서로 다른 로직으로 처리를 해주어야 합니다. 그래서 SHA256 기반의 인증 로직을 갖는 Authentication Provider와 Bcrypto 기반의 인증 로직을 갖는 Authentication Provider를 AuthenticationManager에 등록하여 위의 상황을 해결할 수 있을 것입니다.
https://mangkyu.tistory.com/76](https://mangkyu.tistory.com/76
+ 참고 자료)
https://docs.spring.io/spring-security/reference/servlet/architecture.html
https://mangkyu.tistory.com/76](https://mangkyu.tistory.com/76
'SPRING' 카테고리의 다른 글
[QueryDSL] 정리 및 spring boot에서 사용법 (0) | 2024.01.21 |
---|---|
Swagger 사용방법(feat.springdoc) (1) | 2023.12.30 |
2. Spring Security란? (1) | 2023.12.23 |
1. 인증 방법 - 쿠키,세션,jwt (1) | 2023.12.23 |
Packaging Jar VS War (0) | 2023.12.07 |