Loading...

Spring/Tistory / / 2022. 4. 12. 15:06

블로그-V3. 시큐리티 필터

반응형

 

시큐리티 설정 파일에 의해 /s 주소가 앞에 붙은 요청은 모두 로그인 화면으로 이동하게 된다.

 

package site.metacoding.blogv3.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@EnableWebSecurity // 해당 파일로 시큐리티가 활성화
@Configuration // IoC 등록
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public BCryptPasswordEncoder encode() {
        return new BCryptPasswordEncoder();
    }

    // 인증 설정하는 메서드
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        // super.configure(http); 부모 메서드 안쓸거야!!
        http.csrf().disable(); // 이거 안하면 postman 테스트 못함
        http.authorizeRequests()
                .antMatchers("/s/**").authenticated()
                .anyRequest().permitAll()
                .and()
                .formLogin()
                .loginPage("/login-form")
                .loginProcessingUrl("/login") // login 프로세스를 탄다
                .defaultSuccessUrl("/");
    }
}

 

스프링 시큐리티는 스프링 내부가 아니라 외부에서

서블릿의 필터를 기반으로 동작한다.

 

클라이언트에서 보낸 요청이 디스패쳐 서블릿으로 전달되기 전에 필터를 거치게 된다.

 

클라이언트가 요청을 할 때 항상 필터 체인을 타게 된다.

필터를 넘어갈 때는 chain.dofilter( )를 호출해야 넘어간다.

 

모든 필터를 거치면 최종적으로 디스패쳐 서블릿에게 전달되고,

디스패쳐 서블릿이 컨트롤러를 찾아주는 것이다.

 


 

스프링 시큐리티는 필터의 생명주기를 이용해 인증과 권한 작업을 수행할 수 있다.

세션에 접근할 수 있기 때문이다.

 

필터에서는 DB와 IoC 컨테이너에 접근이 불가능하여 인터셉터를 사용했었다.

그 이유는 DS부터 DB 세션이 열리고, IoC에 접근이 가능하기 때문이다.

 

즉, 필터에서는 인증처리를 할 수 없다.

 

때문에 스프링 시큐리티에서는 DelegatingFilterProxy라는 클래스를 제공하는데

스프링에 등록된 빈을 가져와 의존성을 주입할 수 있다.

 

 

 

시큐리티의 필터는 실제로 필터이기 때문에

위치가 DS 이전에 있어서 IoC 컨테이너에 접근이 되지 않지만,

프록시(Proxy)라는 기술을 이용해 스프링에 등록된 빈을 가져와 의존성을 주입할 수 있다.

필터인데 IoC에 접근이 가능한 것이다.

 

왜 DS부터 IoC 컨테이너에 접근이 가능한지 이유는 몰랑..

이렇게 설계가 되어있다.

 

스프링 시큐리티는 내부적으로 만들어져 있는 /login 주소로 접근하면 인증처리를 진행한다.

 

get 요청이 들어왔을 때 DS까지 와서 doGet( )이 실행되기 직전에 어떠한 작업을 하고 싶을 때

DelegatingFilterProxy 클래스를 하나 만든다.

 

// localhost:8080/login-fom 요청!

class DelegatingFilterProxy {
	public DelegatingFilterProxy() { // 무조건 실행되는 생성자
    }
    
    public void 시큐리티필터실행(시큐리티필터들) {
    	// 11가지 시큐리티 필터 실행!!
    }
}

class DispatcherServlet extends HttpServlet {

	public DispatcherServlet() {
    	init(); // 팩토리패턴!!
        new DelegatingFilterProxy d = new DelegatingFilterProxy();
        d.시큐리티필터실행(시큐리티필터들);
    }
	
    DB연결() {
    }
    
    init() { // 처음에 실행되어야하는 메서드들
    	DB연결();
        a();
        b();
    }

	doGet() {
    	1. 주소분석
        2. 컨트롤러 찾아내서
        3. loginForm(); 호출
    }
    
    doPost() {
    }
    
    doPut() {
    }
    
    doDelete() {
    }
}

 

추측!!

 

DS가 만들어질 때 처음 실행되야하는 여러 가지 메서드들을

init( ) 메서드에 모아 두고 DS의 생성자에 넣어 메서드가 실행되기 전에 실행한다.

 

이를 팩토리 패턴이라고 한다.

팩토리 패턴을 사용하면 메서드의 순서도 제어가 가능하다.

 

이처럼 DS의 생성자에서 DelegatingFilterProxy 클래스를 생성해

시큐리티 필터가 작동하게 만들어져 있을 것이다.

 

개념상 DS 안에 들어와서 실행되지만

DS의 doGet, doPost와 같이 DS가 해야 할 일을 하기 직전에 시큐리티 필터들이 실행되는 것이다.

이렇게 사용하여 필요하면 DB에 연결해 데이터를 가져올 수 있다.

 

실제 프록시의 개념은 시큐리티 필터와 DS를 하나로 묶어서

마치 하나의 DS인 것처럼 속이는 것이다.

 

내가 a라는 곳에 가기 위해 k를 무조건 거쳐야 한다면 k를 프록시(대리인)라고 한다.

a에 도착하고 나서 응답해주고 싶은데 c를 항상 거쳐야 한다면 c도 프록시라고 한다.

 

즉, DelegatingFilterProxy는 필터가 아닌데 필터의 역할을 위임하는 프록시라는 것이다.

 

 


 

 

시큐리티 필터에도 체인이 있다.

필터의 종류가 하나가 아니라 11개가 있다.

 

 

시큐리티 11개의 필터를 통과하면 DS로 가는 것이다.

 

 


 

 

실행될 때 run 메서드가 리턴해주는 context가 바로 스프링 성이다.

 

 

컨텍스트는 모든 걸 다 알고 있어서 스프링이 시작되면서 일어나는 모든 것들을 다 가지고 있다.

이 컨텍스트로 모든 것을 제어할 수 있다.

 

이 컨텍스트의 getBean( ) 메서드로 IoC 컨테이너에 등록되어있는 모든 것을 가져올 수도 있다.

 


 

요청이 들어오면 문지기 통해서 필터 체인을 거치며 기본적으로 필터링하고 빠져나오면

시큐리티 필터로 가서 보안에 관련된 필터 체크를 하는데

얘의 장점은 IoC에 등록된 모든 Bean에 접근이 가능하다는 것이다.

 

IoC에 등록되어있는 모든 객체를 Bean이라고 하는데

Bean에 접근이 필요하다면 시큐리티 필터에 모아두는 것이다.

 

필터는 모든 컨트롤러의 전후를 관리하는데

특정 컨트롤러의 전후를 관리하고 싶다면 인터셉터를 사용하고,

컨트롤러의 메서드 내부의 전후를 관리하고 싶다면 AOP를 사용한다!!!

 


 

프록시의 핵심 : 내가 어딘가로 가려고 할 때 대리인을 통해 목적지에 도달하는 것

 

 

클라이언트가 목적지의 사과를 요청할 때 대리인에게 요청한다.

 

목적지에는 사과가 있을 수도 있고 없을 수도 있다.

 

사과가 있으면 대리인이 목적지에서 사과를 들고 오고,

없으면 대리인이 사과 대신에 promise를 클라이언트에게 돌려준다.

 

Ajax와 같은 원리이다.

 

실제 데이터가 아닌 가짜 데이터를 돌려줄 수 있는 것이다.

 

만약 대리인이 데이터를 돌려주지 않으면 클라이언트가 멍 때리게 된다.

가짜 데이터를 받으면 멍 때리지 않고 아래 코드로 쭉쭉 내려갈 수 있을 것이다.

 

대리인 입장에서는 가짜 데이터를 돌려주고 나서도 목적지에 사과가 도착했는지 계속 확인해야 한다.

 

새로운 스레드로 while을 돌며 리스닝하고 있는 것이다.

그러다가 사과가 도착하면 사과를 클라이언트에게 돌려준다.

 

이 대리인이 프록시이다.

 


 

 

시큐리티 필터에서 가장 첫 번째로 하는 일은

인증을 체크해서 인증된 주소가 들어오면 무조건 /login-form으로 던진다.

 

인증이 됐는지 안됐는지 체크하는 필터가 있다는 말이다.

BasicAuthenticationFilter이다.

 

 

[출처]

 

https://cafe.naver.com/metacoding

 

메타코딩 : 네이버 카페

코린이들의 궁금증

cafe.naver.com

메타 코딩 유튜브

https://www.youtube.com/c/%EB%A9%94%ED%83%80%EC%BD%94%EB%94%A9

 

메타코딩

문의사항 : getinthere@naver.com 인스타그램 : https://www.instagram.com/meta4pm 깃헙 : https://github.com/codingspecialist 유료강좌 : https://www.easyupclass.com

www.youtube.com

 

 

 

 

반응형