[Spring] Spring Security 1도 몰랐던 사람 (2)

말하는 감자·2025년 5월 7일

내일배움캠프

목록 보기
54/73
post-thumbnail

이전 글 : https://velog.io/@tofha054/Spring-Spring-Security-1도-몰랐던-사람

Spring Security 구조


이해하기 정말좋은 사진이있어서 가져와봤다.
여기서 서블릿 컨테이너와 스프링 컨테이너로 나뉘는데,
이것저것 알아보다가 튜터님이 너무 깊게 알 필요가 없다고 해서 요약 팍팍해서 TIL 쓴다.

SpringSecurity 에서는 필터를 만들어낸다
보면 알겠지만 SpringSecurity은 스프링 컨테이너에 존재한다.
물론 Bean으로 등록되어있음!!!!

그럼 서블릿 컨테이너에 있는 필터체인에서는 어떻게 SpringSecurity가 만들어낸 필터로 접근하지?

이 역할을 DelegatingFilterProxy가 해준다.








Filter 흐름

필터부분만 떼서보면 이런형식이다.
서블릿 컨테이너에서는 기존에 있던 필터를 진행하다가
DelegatingFilterProxy를 만나면 필터의 흐름이 변하게된다.

그럼 해당 DelegatingFilterProxy 차례에서 SecurityFilterChain을 호출하게 되고, SecurityFilter 끝까지 도달하면
SecurityFilterChain 전체에 대해서 값이 true/false가 나오게되는데 여기서 예외를 반환하거나 다음 필터(Filter2)으로 진행한다.





DelegatingFilterProxy에는 FilterCainProxy라는 놈이있다.!

DelegatingFilterProxy : 아지금 스프링 시큐리티에서 필터만들어서 연결좀할게!
FilterCainProxy : 그 필터들은 여기있어!

요런 느낌?
그럼 스프링 시큐리티에서 우리는 뭘해야하느냐?








SecurityFilterChain에서는 뭘해야하는지?

세션에서 본 그림이다.
해당 요소들은 모두 Filter처럼 생각할 수 있고, 이를 설정하는 클래스가 SecurityConfig 클래스이다.
우리가 자주 사용하는 JWT 토큰에 대해 인가 작업을 실행하는 BearerTokenProvider와 구글,네이버,카카오 등의 OAuth 를 사용할 때 인가에 필요한 작업을 하는 OAuthProvider 등도 여기서 볼 수 있음.

SecurityFilterChain에서는 최종적인 목표가 SecurityContextHolder의 내용을 채우는 것이다.

아래에 곧 나올 그림은 SecurityFilterChain의 모든 필터들인데 Spring Security가 기본적으로 모두 제공하고있다.

여기서 의문
우리가 프로젝트에서 사용하던 jwtFilter에서는 바로 SecurityContextHolder를 채우는뎅??

jwtFilter에서 많이 써봤을 사람도있겠는데...
우리가 정의하는 필터에서 바로 ContextHolder내용을 채우고있다.

그리고 이 내용이 있다면 SecurityConfig에도 아래와 같은 코드가 있을 것이다.

이는 ContextHolder내용을 채우는 jwtFilter를 SecurityFilterChain에 있는 필터들 순서 중에 UsernamePasswordAuthenticationFilter라는 클래스 에다가 위치시키는 것이다.

이 순서로 진행된다.
오른쪽의 구현체는 우리가 알필요가 읍슴 필요하면 찾아서 꺼내쓰는 형식이기땜시
이처럼 앞 필터에서 SecurityContextHolder가 충족되면 다음 필터들은 모두 패스된다
패스된 필터들은 어디로가는가???

서블릿 컨테이너로 돌아와서 다음 필터를 진행한다.
혹은 오류 반환을 한다.








UserDetails

위에서 봤던 사진을 확대해봤는데,
Authentication에는 Principle이라는 객체가 존재한다. (우리가 쓰는 @AuthenticationPrinciple 이 이 Principle이다.)

SecurityContext
└── Authentication
├── authorities (권한들)
├── details (IP, 세션 등)
├── credentials (비밀번호 or 토큰)
└── principal ← 로그인한 사람 정보 (중요)

일케생김

이처럼, Principal은 “로그인한 사용자 자신”을 나타내는 객체다.

Spring Security가 로그인 성공 시, 이 Principal 객체를 Authentication 안에 넣어주는데 우리는 jwtFilter에서 바로 집어넣고잇음..

            Authentication auth = new UsernamePasswordAuthenticationToken(
                    authUser,
                    null,
                    List.of(new SimpleGrantedAuthority(authUser.getUserRole().name())) // 역할 기반 권한 리스트
            );

이런식으로 ㅇ_ㅇ

여기서는 커스텀한 로그인 객체를 넣어주지만, 아주 간단한 아이디/비밀번호/역할권한정보 에 관한 내용만 저장할 것이라면
UserDetails 인터페이스를 활용할 수 있음.

메서드설명
getUsername()아이디(이메일 등)
getPassword()비밀번호
getAuthorities()역할/권한 정보 (ROLE_USER, ROLE_ADMIN 등)
isAccountNonExpired()계정 만료 여부
isAccountNonLocked()잠긴 계정인지
isEnabled()활성 계정인지




왜 이걸 쓰냐?

  • Spring Security가 내부에서 로그인 인증 처리를 할 때 UserDetails 타입을 기대함
  • 그래서 우리가 만든 User 엔티티가 이 인터페이스를 구현하게 하면 좋음

이로써 스프링 시큐리티 로 큰 흐름그리기 작동 순서정도 를 하루종일 배웠따ㅣ..

profile
대충 데굴데굴 굴러가는 개발?자

4개의 댓글

comment-user-thumbnail
2025년 5월 8일

시큐리티 항상 느끼지만 너무 복잡하고 어려워요. 그래도 덕분에 조금이나마 이해 하고 가요

답글 달기
comment-user-thumbnail
2025년 5월 9일

여기서는 커스텀한 로그인 객체를 넣어주지만, 아주 간단한 아이디/비밀번호/역할권한정보 에 관한 내용만 저장할 것이라면 UserDetails 인터페이스를 활용할 수 있음.

이 부분에서 꼭 UserDetails 를 사용해야하는 이유가 있는걸까요?
principal 자체는 Object 타입이라 원하는 필드들로 구성된 클래스를 직접 정의해 사용해도 괜찮을것 같은데, 어떤 의도인지 궁금해 코멘트 남겨봅니다! (UserDetails 인터페이스에는 요구사항에 필요하지 않은 추상 메소드들이 많아 강제되는것 같아보이는것 같습니다)

1개의 답글