1. Spring Security 란
스프링 기반의 애플리케이션의 보안(인증과 권한, 인가 등)을 담당하는 스프링 하위 프레임워크
용어정리
- 인증 : Authentication. 사용자의 신원을 검증하는 프로세스
- ex) 로그인
- 인가 : Authorization. 인증된 사용자가 어떠한 자원에 접근할 수 있는지를 확인하는 절차
- ex) 관리자 페이지는 관리자만 들어갈 수 있고 일반 유저는 들어갈 수 없음
- 즉, 인증이 먼저 이루어지고 인가가 이뤄져야 한다.
Spring Security에서는 이러한 인증, 인가를 위해 Principal을 아이디로 Credential을 비밀번호로 사용하는 Credential 기반의 인증방식을 사용한다.
2. Servlet Filter
스프링 시큐리티는 서블릿의 필터를 기반으로 동작한다. 사용자의 요청이 서블릿에 전달되기 전, 스프링 시큐리티는 필터의 생명주기를 이용해서 인증과 권한 작업을 수행한다. 그러나 필터는 Dispathcher Servlet으로 가기 전에 적용되므로, 스프링 컨테이너에 등록된 빈을 인식할 수 없다.
따라서 스프링 시큐리티에서는 DelegatingFilterProxy라는 서블릿 필터의 구현제를 제공한다. DelegatingFilterProxy 는 서블릿 매커니즘으로 서블릿의 필터로 등록될 수 있으며, 스프링에 등록된 빈을 가져와서 의존성 주입을 할 수 있다. 결론적으로 서블릿 컨테이너의 생명주기와 스프링의 ApplicationContext 사이를 연결하는 다리 역할을 하게된다.
FilterChainProxy
- DelegatingFilterProxy 를 통해 받은 요청과 응답을 스프링 시큐리티 필터체인에 전달하고 작업을 위임하는 역할을 한다.
- 서블릿을 지원하는 시작점 역할을 하기 위해 DelegatingFilterProxy에서 SecurityFilterChain을 바로 실행하지 않고 FilterChainProxy를 두었다. 이로인해 서블릿에서 문제가 발생하는 경우 FilterChainProxy의 문제라는 것을 알 수 있다.
- 어떤 체인에게 작업을 위임할지도 결정할 수 있다.
SecurityFilterChain
- 인증을 처리하는 여러 개의 시큐리티 필터를 담는 필터 체인
- 여러 개의 SecurityFilterChain을 구성하여 매칭되는 URL에 따라 다른 SecurityFilterChain이 사용되도록 할 수 있다.
SecurityFilters
- 요청을 스프링 시큐리티 매커니즘에 따라 처리하는 필터
- 순서가 존재한다.
2-1. 인증관련 architecture
- Username and Password 방식의 아키텍처는 다음과 같다.
- spring security 는 기본적으로 세션-쿠키 방식으로 인증한다
- 유저가 로그인 요청 (Http Request)
- AuthenticationFilter 에서 사용자 아이디와 패스워드를 인증용객체 UsernamePasswordAuthentication Token으로 생성하여 AuthenticationManager 에 전달
- AuthenticationManager 은 등록된 AuthenticationProvider 들을 조회하여 인증 요구
- AuthenticationProvider 은 UserDetailService 를 통해 입력받은 아이디에 대한 사용자 정보를 User(DB) 에서 조회
- User 에 로그인 요청한 정보가 있는 경우 UserDetails 로 꺼내서 유저 session 생성
- 인증이 성공된 UsernameAuthenticationToken 을 생성하여 AuthenticationManager 로 반환
- AuthenticationManager 은 UsernameAuthenticationToken 을 AuthenticationFilter 로 전달
- AuthenticationFilter 은 전달받은 UsernameAuthentication 을 LoginSuccessHandler 로 전송하고, spring security 인메모리 세션저장소인 SecurityContextHolder 에 저장
- 유저에게 session ID 와 응답을 내려줌
Spring Security 주요 모듈
- AuthenticationFilter
- Spring Security 는 연결된 필터를 가지고 있음
- 모든 Request 는 인증과 인가를 위해서 이 필터를 통과
- SecurityContext 에 사용자의 세션 ID 가 있는지 확인 하고 세션 ID 가 없는 경우 다음 로직 수행
- 인증 성공하는 경우 인증된 Authentication 객체를 SecurityContext 에 저장 후 AuthenticationSuccessHandler 실행
- 인증 실패하는 경우 AuthenticationFailureHandler 실행
- UsernamePasswordAuthentication Token
- Authentication을 구현한 AbstractAuthenticationToken의 하위 클래스
- principal -> username (유저의 아이디) / credentials -> password (유저의 패스워드)
- 인증용 객체를 생성한다.
- UsernamePasswordAuthenticationToken(Object principal, Object credentials) : 인증 전의 객체를 생성
- UsernamePasswordAuthenticationToken(Object principal, Object credentials,Collection<? extends GrantedAuthority> authorities) : 인증 완료된 객체를 생성
public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {
private final Object principal;
private Object credentials;
// 인증 완료 전의 객체 생성
public UsernamePasswordAuthenticationToken(Object principal, Object credentials) {
super(null);
this.principal = principal;
this.credentials = credentials;
setAuthenticated(false);
}
// 인증 완료 후의 객체 생성
public UsernamePasswordAuthenticationToken(Object principal, Object credentials,
Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
this.credentials = credentials;
super.setAuthenticated(true); // must use super, as we override
}
}
public abstract class AbstractAuthenticationToken implements Authentication, CredentialsContainer {
}
- AuthenticationManager
- Authentication 을 만들고 인증을 처리하는 interface
- 로그인시 인자로 받은 Authentication 을 Provider 를 통해 유효한지 처리하여 Authentication 객체를 리턴한다.
- prividerManager
- AuthenticationManager의 구현체
- 사용자 요청을 인증에 필요한 AuthenticationProvider 를 살펴보고 전달된 인증 객체를 기반으로 사용자 인증 시도
public interface AuthenticationManager {
Authentication authenticate(Authentication authentication)
throws AuthenticationException;
}
- AuthenticationProvider
- 실제 인증을 담당하는 인터페이스
- 인증 전 Authentication 객체를 받아서 DB 에 있는 사용자 정보를 비교하고 인증된 객체를 반환
- UserDetailsService
- DB 에서 유저 정보를 가져오는 역할
- loadUserByUsername() 메소드를 통해서 DB 에서 유저 정보를 가져온다.
- 일반적으로 이를 구현한 클래스의 내부에 UserRepository를 주입받아 DB와 연결하여 처리한다.
public interface UserDetailsService {
UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
}
- userDetails
- 인증에 성공하여 생성된 UserDetails 객체는 Authentication객체를 구현한 UsernamePasswordAuthenticationToken을 생성하기 위해 사용된다.
- UserDetails 인터페이스를 살펴보면 아래와 같이 정보를 반환하는 메소드를 가지고 있다. UserDetails 인터페이스의 경우 직접 개발한 UserVO 모델에 UserDetails를 implements하여 이를 처리하거나 UserDetailsVO에 UserDetails를 implements하여 처리할 수 있다.
public interface UserDetails extends Serializable {
Collection<? extends GrantedAuthority> getAuthorities(); //계정의 권한 목록을 리턴
String getPassword();
String getUsername();
boolean isAccountNonExpired(); //계정의 만료 여부 리턴
boolean isAccountNonLocked(); //계정의 잠김 여부 리턴
boolean isCredentialsNonExpired(); //비밀번호 만료 여부 리턴
boolean isEnabled(); //계정의 활성화 여부 리턴
}
- SecurityContextHolder
SecurityContextHolder
- SecurityContext 를 현재 스레드와 연결 시켜주는 역할
- 스프링 시큐리티는 같은 스레드 의 어플리케이션 내 어디서든 SecurityContextHolder 의 인증 정보를 확인 가능하도록 구현되어 있는데 이 개념을 ThreadLocal 이라고 함.
SecurityContext
- Authentication 의 정보를 가지고 있는 interface
- SecurityContextHolder.getContext() 를 통해 얻을 수 있음
Authentication
- 현재 접근하는 주체의 정보와 권한을 담는 인터페이스
- AuthenticationManager.authenticate(Authentication) 에 의해 인증된 principal 혹은 token
출저
'Spring' 카테고리의 다른 글
[Spring] Custom exception로 공통 예외 처리하기(feat. @ExceptionHandler, @ControllerAdvice) (0) | 2024.05.07 |
---|---|
스프링 배치(Spring Batch)로 대용량 데이터 관리하기 (0) | 2024.04.01 |
[Spring] Servlet 과 Spring (0) | 2023.02.06 |
[Spring] 빈 스코프 (0) | 2023.02.01 |
[Spring] 빈 생명주기 콜백 (0) | 2023.01.30 |