서블릿 필터는 스프링에서 정의된 빈을 주입해서 사용할 수 없다. ( 필터 - 요청을 받아서 자원을 접근하기 전후에 일정한 작업을 처리하는 클래스 이다. ) 서블릿 필터와 스프링 빈은 서로 다른 컨테이너 상에서 동작하므로 주입이 불가한 것이다. 인증/인가와 같은 처리는 스프링 컨테이너에서 생성된 Filter를 통해 처리된다. DelegatingFilterProxy는 실질적인 서블릿 필터로서 특정한 이름을 가진 스프링 빈을 찾아 그 빈에게 요청을 위임한다. springSecuirityFilterChain이름으로 생성된 빈을 ApplicationContext 에서 찾아 요청을 위임하며 실제 보안 처리를 하지 않는다.
서블릿 컨테이너와 스프링 컨테이너 사이의 링크를 제공해주는 서블릿 필터로서 서블릿 필터의 요청을 받아 스프링 컨테이너에 생성된 Filter를 구현한 스프링 빈에 위임한다.
springSecurityFilterChain의 이름으로 생성되는 필터 빈이다. DelegatingFilterProxy로 부터 요청을 위임받고 실제 보안을 처리한다. 스프링 시큐리티 초기화 시 생성되는 필터들을 관리하고 제어한다.(스프링 시큐리티가 기본적으로 생성하는 필터 + 설정 클래스에서 API추가시 생성되는 필터) 사용자의 요청을 필터 순서대로 호출하여 저장한다. 사용자 정의 필터를 생성해서 기존의 필터 전후로 추가가 가능하며(필터의 순서를 잘 정의해야 한다.) 마지막 필터까지 인증 및 인가 예외가 발생하지 않으면 보안을 통과한다.
WebSecurityCOnfiugerAdapter를 상속받은 설정 클래스가 여러개 일 경우 설정클래스 별로 보안 기능이 각각 작동하며 설정 클래스별로 RequestMatcher와 필터가 생성된다. RequestMatcher와 filter들을 SecurityFilterChain객체에 담겨 있으며 설정 클래스별로 존재하고 여러 설정클래스가 존재할 경우 해당 객체여러개를 FilterChainProxy가 리스트로 가지고 있게 된다. 그래서 , 사용자의 요청이 들어올 경우 FilterChainProxy의 SecurityFilterChains 중 Request에 따라 해당하는 Filters를 선택하여 실행해주게 된다.
스프링 시큐리티가 초기화 될때 순서에 따라 초기화하기 때문에 설정 클래스가 여러개일 경우 @Order(0),(1) 등으로 순서를 지정해주어야 한다. 넓은범위의 요청방식이 순서가 더 낮아야 한다. 좁은 범위의 요청방식이 우선순위가 더높아야만 먼저 체크를 하므로 좁은 범위의 보안 적용이 가능하다.
인증 또는 인증 주체 라고 정의할 수 있으며, 당신이 누구인지 증명하는 것이다.
Authentication authentication = SecurityContexHolder.getContext().getAuthentication()
로 작성하면 Authentication 객체를 얻을 수 있다. --> 전역적으로 인증 결과 참조Authentication 인터페이스의 구조
1. principal : 사용자 아이디(인증시) 혹은 User 객체(인증 후)를 저장
2. credentials : 사용자 비밀번호
3. authorities : 인증된 사용자의 권한 목록
4. details : 인증 부가 정보
5. Authenticated : 인증 여부 , 인증시 true저장
Authentication : 인증 정보를 저장하는 토큰 개념, 인증 시/후 에 담는 정보가 다르다.
Authentication 객체가 저장되는 보관소로 필요 시 언제든지 Authentication 객체를 꺼내어 쓸 수 있도록 제공되는 클래스이다. ThreadLocal에 저장되어 아무 곳에서나 참조가 가능하도록 설계되었다. 인증이 완료되면 HttpSession에 저장되어 어플리케이션 전반에 걸쳐 전역적인 참조가 가능하다.
SecurityContext에 Authentication 객체가 저장되고 해당 객체 내에 User객체의 정보가 저장된다. user는 인증 성공시 최종으로 생성된 사용자의 정보이다.
SecurityContext 객체 저장 방식
SecurityContextHolder.clearContext() : SecurityContext 기존 정보 초기화
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
모드 변경
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);