Spring/Security
Spring Security : Spring Security 개념 및 필터들
짱엉
2024. 7. 10. 23:32
728x90
Spring Security(스프링 시큐리티) 란?
애플리케이션 내의 보안 중 사용자에 대한 ‘인증’과 ‘인가’에 대한 처리를 담당하는 프레임워크를 의미한다.
- 접근 주체(Principal)
- 보호된 대상에 접근하는 유저
- 인증(Authenticate)
- 현재 유저가 누구인지 확인 (ex 로그인)
- 애플리케이션의 작업을 수행할 수 있는 주체임을 증명한다.
- 인가(Authorization)
- 현재 유저가 어떤 서비스, 페이지에 접근할 수 있는 권한이 있는지 검사한다.
- 어떤것을 할 수 있는지
- 권한 부여(Authorization)
- 인증된 주체가 애플리케이션의 동작을 수행할 수 있도록 허락되었는지를 결정
- 권한 승인이 필요한 부분으로 접근하려면 인증 과정을 통해 주체가 증명되어야 한다.
- 권한 부여에도 두가지 영역이 존재하는데 웹 요청 권한, 메소드 호출 및 도메인 인스턴스에 대한 접근 권한 부여
스프링 시큐리티 특징과 구조
스프링 시큐리티에서는 주로 서블렛 필터(Filter)와 이들로 구성된 필터체인, 그리고 필터체인들로 구성된 위임모델을 사용한다.
Client (request) → Filter → DispatcherServlet → Interceptor → Controller
- 인증 관리자 ⇒ UsernamePasswordAuthenticationFilter
- 접근 결정 관리자 ⇒ FilterSecurityInterceptor
- 보안과 관련하여 체계적으로 많은 옵션을 제공하여 편리하게 사용할 수 있다.
- Filter 기반으로 동작하여 MVC와 분리하여 동작한다.
- 어노테이션을 통한 간단한 설정
- 기본적으로 Session & Coockie 방식으로 인증한다.
⚠️ Spring Security 5.7.x 버전에 대한 이슈 사항
public class SecurityConfig extends WebSecurityConfigurerAdapter{}
- 5.6.x 버전 이하에서는 WebSecurityConfig 클래스에서 WebSecurityConfiguredAdapter를 상속받아서 사용했다
- 5.7.x 버전부터는 Deprecated되어서 사용이 안됨!
- 5.7.x 버전 이상부터는 컴포넌트 기반의 Configuration을 구성하는 것으로 권장된다.
Spring Security Authentication Architecture
- 사용자가 로그인 정보와 함께 인증 요청을 한다 → Http Request (사용자가 Form을 통해 로그인 정보를 입력하고 인증 요청을 보낸다.)
- AuthenticationFilter(사용할 구현체 UsernamePasswordAuthenticationFilter)가 HttpServletRequest에서 사용자가 보낸 아이디와 패스워드를 인터셉트(가로챈다, 확인)한다. 가로챈 정보를 통해 UsernamePasswordAuthenticationToken의 인증용 객체를 생성한다.
- HttpServletRequest에서 꺼내온 사용자 아이디와 패스워드를 진짜 인증을 담당할 AuthenticationManager인터페이스(구현체 - ProviderManager)에게 인증용 객체(UsernamePasswordAuthenticationToken) 객체를 전달한다.
- AuthenticationManager는 AuthenticationFilter에게 인증용 객체(UsernamePasswordAuthenticationToken)을 전달받는다.
- 실제 인증을 할 AuthenticationProvider에게 Authentication객체(UsernamePasswordAuthenticationToken)을 다시 전달한다.
- AuthenticationManager는 등록된 AuthenticationProvider(들)을 조회하여 인증을 요구한다.
- 실제 DB에서 사용자 인증정보를 가져오는 UserDetailService에 사용자 정보를 넘겨준다.
- DB에서 인증에 사용할 사용자 정보(사용자 아이디, 암호화된 패스워드, 권한 등)를 UserDetails라는 객체로 전달 받는다.
- UserDetailsService는 인터페이스이다.
- 즉, 해당 인터페이스를 구현한 빈(Bean)을 생성하면 스프링 시큐리티는 해당 빈을 사용하게 된다.
- UserDetailsService는 로그인한 ID에 해당하는 정보를 DB에서 읽어들여 UserDetails 객체를 만들어 세션에 저장한다.
- AuthenticationProvider는 UserDetails 객체를 전달 받은 이후 실제 사용자의 입력 정보와 UserDetails 객체를 가지고 인증을 시도한다.
- 인증이 완료되면 권한 등의 사용자 정보를 담긴 Authentication 객체를 반환한다.
- 다시 최초의 AuthenticationFilter에 Authentication 객체가 반환된다.
- Authentication 객체를 인메모리 세션저장소인 SecurityContextHolder에 담는다.
- 클라이언트(유저)에게 session ID(JSESSION ID)와 함께 응답을 한다. 이후 요청에서는 요청 쿠키에서 JSESSION ID정보를 통해 이미 로그인 정보가 저장되어 있는지 확인하고 이미 저장되어 있고 유효하면 인증처리를 한다.
- 성공시 AuthenticationSuccessHandle를 실행한다.
- 실패시 AuthenticationFailureHandler를 실행한다.
- 사용자 정보를 저장한다는건 Session-Cookie 방식을 사용한다는걸 의미한다.
1. AuthenticationManager - 인증 담당
- 유저의 요청을 AuthenticationFilter에서 Authentication 객체로 변환해 AuthenticationManager(ProviderManager)에게 넘겨주고, AuthenticationProvider(DaoAuthenticationProvider)가 실제 인증을 한 이후에 인증이 완료되면 Authentication객체를 반환해준다.
- AbstractAuthenticationProcessingFilter: 웹 기반 인증요청에서 사용되는 컴포넌트로 POST 폼 데이터를 포함하는 요청을 처리한다. 사용자 비밀번호를 다른 필터로 전달하기 위해서 Authentication 객체를 생성하고 일부 프로퍼티를 설정한다.
- AuthenticationManager: 인증요청을 받고 Authentication을 채워준다.
- AuthenticationProvider: 실제 인증이 일어나고 만약 인증 성공시 Authentication 객체의 authenticated = true로 설정해준다.
- Spring Security 는 ProviderManager라는 AuthenticationManager인터페이스의 유일한 구현체를 제공한다. ProviderManager 는 하나 또는 여러 개의 AuthenticationProvider 구현체를 사용할 수 있다. AuthenticationProvider는 많이 사용되고 ProviderManager(AuthenticationManager 의 구현체) 와도 잘 통합되기 때문에 기본적으로 어떻게 동작하는 지 이해하는 것이 중요하다.
2. Security Context Holder
- Spring Security는 인증이 완료되면 아이디, 패스워드를 가진 사용자의 principal 과 credential 정보를 Authentication에 담는다.
- 그 Authentication 정보를 Security Context에 보관한다.
- 그리고 그 Security Context를 Security Context Holder에 담아 보관한다.
- 때문에, 사용자의 정보를 얻기 위한 코드는 다음과 같다.
Object principal = SecurityContextHolder.getContext.getAuthentication.getPrincipal();
if(principal instanceof UserDetails) {
String username = ((UserDetails)principal).getUsername();
} else {
String username = principal.toString();
}
3. Password Authentication
- DaoAuthenticationProvider 는 UserDetailsService 타입 오브젝트로 위임한다. UserDetailsService 는 UserDetails 구현체를 리턴하는 역할을 한다.
- UserDetails 인터페이스는 이전에 설명한 Authentication 인터페이스와 상당히 유사하지만 서로 다른 목적을 가진 인터페이스이므로 헷갈리면 안된다.
- Authentication : 사용자 ID, 패스워드와 인증 요청 컨텍스트에 대한 정보를 가지고 있다. 인증 이후의 사용자 상세정보와 같은 UserDetails 타입 오브젝트를 포함할 수도 있다.
- UserDetails: 이름, 이메일, 전화번호와 같은 사용자 프로파일 정보를 저장하기 위한 용도로 사용
Spring Security Filter
Clinet -> FilterChain -> DelegatingFilterProxy (위임처리) -> FilterChainProxy -> Security Filter Chain(시큐리티 필터 적용!)
- Spring Container와 Was 서버간에 Request 요청이 연결되어야 하는데 이를 수행하는 Filter가 DelegationFilterProxy다.
- DelegatingFilterProxy의 내부에 FilterChainProxy라는 위임대상을 가지고 있다.
- FilterChainProxy는 SpringSecurity에서 제공되는 특수 필터다.
- SecurityFilterChain이라는 이름을 가진 Bean을 호출하여 SecurityFilter 역할을 수행한다.
- 클라이언트(보통 브라우저)는 요청을 보내게 되고, 그 요청을 서블릿이나 JSP등이 처리하게 된다. 스프링 MVC에서는 요청을 먼저 받는것이 DispatcherServlet 이다.
- 이 DispatcherServlet이 요청 받기 전에 다양한 필터들이 있을 수 있다.
- 필터가 하는 역할은 클라이언트와 자원 사이에서 요청과 응답 정보를 이용해 다양한 처리를 하는데 목적이 있다.
- 어떤 필터는 요청을 받은 후, 클라이언트가 원래 요청한 자원이 아닌 다른 자원으로 리다이렉트 시킬 수도 있다.
- 또 다른 어떤 필터는 다음 필터에게 요청과 응답을 전달하지 않고, 바로 클라이언트에게 응답하고 끝낼 수 도 있다.
- 스프링 시큐리티는 다양한 기능을 가진 필터들을 10개 이상 기본적으로 제공한다.
- 이렇게 제공되는 필터들을 Security Filter Chain(시큐리티 필터 체인) 이라고 말한다.
SecurityFilterChain
SecurityFilterChain은 List의 형태로 구성되며, 이 리스트를 AuthenticationFilter라 부른다!
- (UsernamePassword)AuthenticationFilter : (아이디와 비밀번호를 사용하는 form 기반 인증) 설정된 로그인 URL로 오는 요청을 감시하며, 유저 인증 처리함
-
- AuthenticationManager를 통한 인증 실행
- 인증 성공 시, 얻은 Authentication 객체를 SecurityContext에 저장 후 AuthenticationSuccessHandler 실행
- 인증 실패 시, AuthenticationFailureHandler 실행
728x90