인천국제공항에서 배운 보안(Spring Security)

KUN·2025년 5월 28일

목적

위와 같은 글을 예전에 작성한 적이 있다.

JWT에 대해 완벽히 이해하고 있는 것은 아니지만, 
실무에서는 Spring Security와 함께 사용하는 경우가 많다는 것을 알게 되었다.
그래서 오늘은 JWT와 연동하기 위해서라도 꼭 알아야 할 Spring Security에 대해 정리하고자 한다.

Spring Security

무엇 인가?

공식 문서

Spring Security는 인증(Authentication), 인가(Authorization), 
그리고 일반적인 공격으로부터의 보호를 제공하는 프레임워크입니다.
명령형 애플리케이션과 반응형 애플리케이션 모두에 대해 보안을 지원하며,
Spring 기반 애플리케이션 보안의 사실상 표준으로 자리 잡고 있습니다.

구조 - Spring Security Reference


1. 사용자의 요청 (Request)
클라이언트가 /login, /mypage, /admin 등 특정 자원에 접근을 시도한다.
이 요청은 Spring Security의 Filter Chain을 통과하게 된다.

2. Security Filter Chain 진입
FilterChainProxy가 요청을 가로채고 내부에 등록된 여러 보안 필터를 순서대로 실행한다.

주요 필터 예시
  ExceptionTranslationFilter
  UsernamePasswordAuthenticationFilter
  SecurityContextPersistenceFilter
  그 외 다양한 커스텀 및 내장 필터

3. 인증(Authentication)
로그인 요청인 경우 UsernamePasswordAuthenticationFilter가 작동한다.
AuthenticationManager가 인증 처리를 위임받고, 
내부적으로 AuthenticationProvider를 통해 인증을 수행한다.
UserDetailsService를 통해 사용자 정보를 로드하고, PasswordEncoder를 사용해 비밀번호 일치를 검증한다.
인증 성공 시 Authentication 객체가 생성된다.

4. SecurityContext 저장
인증된 사용자의 정보는 SecurityContextHolder에 저장된다.
이후의 모든 요청은 이 컨텍스트를 기반으로 인증 정보를 참조한다.

5. 인가(Authorization)
인증된 사용자가 해당 자원에 접근할 수 있는 권한이 있는지 검사한다.
AccessDecisionManager가 역할(Role) 기반으로 접근 가능 여부를 판단한다.
예시)
  ROLE_ADMIN만 접근 가능한 페이지인가?
  @PreAuthorize("hasRole('USER')") 조건을 만족하는가?

6. 접근 허용 또는 거부
권한이 있으면 요청이 컨트롤러로 전달된다.
권한이 없으면 AccessDeniedException이 발생한다.
예외는 ExceptionTranslationFilter가 감지하고 403 응답 등을 반환한다.

어려운 것이 당연하다.
그래서 쉽게 비유를 해보자.

당신은 스프링 여행을 가기 위해 비행기 표를 예매했다.
드디어 출국 당일! 설레는 마음으로 인천국제공항에 도착한다.

수하물 위탁 후 출국을 위해 보안 검사를 받아야한다.

보안검색에서는 이런 걸 확인한다.
첫번째로 탑승권이 진짜인지 확인한다.
두번째로 소지품 검사가 있다.
세번째로 여권 소유자가 본인과 일치하는 지 검사한다.

이 과정을 모두 통과해야만 출국장(or 면세구역)으로 들어갈 수 있다.
이 면세구역에 있는 사람은 "인증된 사람" 으로 면세점을 이용할때 마다 보안검사를 하지 않는다.

로그인 요청 - 탑승권 제시
비밀번호 확인 - 본인 확인
위험 요청 차단 - 소지품 검사
인증 성공 - SecurityContext에 사용자 정보 저장
면세구역 진입 - 인증된 상태로 서버가 인식

Spring Security - 공항 전체 보안 시스템

  • Filter : 출입문마다 서 있는 보안 요원들
  • 인증(Authentication) : 여권 검사 & 본인 확인
  • 인가(Authorization) : 특정 구역 출입 가능 여부 판단
  • 보안 컨텍스트(SecurityContext) : "이 사람 이미 통과했어요"라는 내부 메모
  • 사용자 정보 서비스(UserDetailsService) : 탑승자 명단 서버 (탑승객 정보 조회)
  • 비밀번호 인코더(PasswordEncoder) : 여권 진위 확인 장비 (위조 방지)

사용해보자

# 1번째 - 의존성 추가

최근이면서 가장 다운로드가 수가 많은 3.4.2 버전을 선택했다.

저 의존성을 넣고 아무것도 안하고 실행한 후 localhost:8080 으로 접속하면 이렇게 뜬다.

콘솔 로그에 비밀번호가 자동으로 뜬다.

입력하면

localhost:8080 에 드디어 접속할 수 있게 된다.

대충 잘 적용되었다는 소리다.

# 2번째 - SecurityConfig 인가작업

매우 잘 된다.

여기서 잘 봐야할 점은 requestMatchers 라는 부분이다.

requestMatchers? - 요청 URL마다 인가 규칙을 정의한다.
위 코드를 예시를 들면 다음과 같이 정리된다.

1. permitAll() - //login 은 누구나 접근이 된다.
2. hasRole() - ADMIN 권한이 었어야 /admin 접근이 된다.
3. hasAnyRold() - /my 와 하위 경로는 ADMIN 또는 USER 권한여야 한다.
4. authenticated() - 그 외 모든 요청은 로그인(인증) 만 되어있으면 허용 한다.

기타 등등...

해당 내용과 관련된 공식주소

# 3번째 - SecurityConfig 회원가입과 로그인 설정

RestController 로 구현하기 좀 힘들었다.

대부분의 블로그나 유튜브가 Controller 로 구현되어 있어서 RestController 의 사용법을 찾기 어려웠다.

https://padosol.tistory.com/69 해당 블로그의 도움을 받아 만들어보았다.

컨픽을 이렇게 바꾸고....

passwordEncoder() <- 비밀번호 암호화
authenticationManger() <- REST 방식 로그인 컨트롤러에서 인증을 처리하게 위해 작성

서비스 클레스는 만들지 않았다. ( 보여주기 위함 ) - 회원가입

마찬가지로 서비스 클레스는 만들지 않았다. - 로그인
아직 JWT 를 사용하지 않기 때문에 세션을 사용해서 정보를 저장한다.

# 4번째 - 테스트하기

회원가입 성공

회원가입 실패

로그인 성공

로그인 실패

세션에 잘 저장되었는 지 확인


의문점

나는 아무것도 보내주지 않았는데 어떻게 Authentication 을 받을 수 있는가?

결론은 Spring Security가 자동 주입해준다.
공식자료 - Spring Method Arguments


배운점

Spring Security를 배우다 보면, 처음엔 헷갈리는 부분이 있다.
그중 하나가 바로 "이 설정들도 요청이 올 때마다 실행되는 걸까?" 라는 의문이었다.

왜냐하면 Spring Security는 결국 필터 기반 구조이고,
요청이 들어오면 필터 체인을 거치게 되어 있기 때문이다.

그런데 나는 지금까지 직접 Filter 클래스를 만든 적이 한 번도 없었다.
"내가 필터를 등록하지도 않았는데, 어떻게 필터처럼 동작하지?" 라는 의문이 생겼던 것이다.

해당 블로그를 보면서도 이게 "왜 이렇게 되는거지?" 라는 생각을 많이 했었다.
하지만, 정작 몇 시간을 걸쳐서 계속해서 확인해보고 흐름을 파악할 결과는 다음과 같다.

사실 나는 초반에 @Configuration으로 보안 설정을 구성해두었고,
이 설정 클래스 내부에서 SecurityFilterChain을 정의해 두었다.

즉, 서버가 시작될 때
내가 만든 Security 설정은 필터 체인에 등록된다.

이후 실제 요청이 들어올 때마다
Spring Security는 이 필터 체인을 기반으로
내가 설정한 인증/인가 규칙을 실행한다.

이것이 내 결론이다.

profile
배우노라, 실험하노라, 기록하노라

0개의 댓글