Contents
1. 스프링 시큐리티란?2. 스프링 시큐리티 필터 체인3. 프록시 패턴과 Spring Security4. 인증과 인가 로직 (Form Login 흐름)5. 주요 필터 종류 정리6. FormLogin vs HTTP Basic7. JWT 기반 로그인 (간단 요약)🔗 참고 자료✅ SecurityContextHolder란?🧠 작동 원리 요약🔐 내부 구조 요약📦 왜 ThreadLocal 기반인가?✅ 로그인 후 인증 객체 접근 예시📌 한 줄 요약🔄 그림으로 전체 요청 흐름 요약🌐 전체 요청 처리 흐름 요약 (Spring MVC + Spring Security)SecurityConfig
package com.metacoding.securityapp1.core;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
// 예: localhost:8080/user/asdasd, localhost:8080/user/join-form
@Configuration // 이 클래스는 스프링 설정 클래스임을 명시 (빈 등록 용도)
public class SecurityConfig {
// 비밀번호 암호화를 위한 단방향 해시 함수 (회원가입/로그인 시 사용)
@Bean
public BCryptPasswordEncoder encodePwd() {
return new BCryptPasswordEncoder();
}
@Bean // SecurityFilterChain을 빈으로 등록하여 보안 설정을 적용함
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// H2 Console은 iframe으로 동작하므로, 기본적으로 막혀있는 iframe을 sameOrigin으로 허용함
http.headers(headers -> headers.frameOptions(frameOptions -> frameOptions.sameOrigin()));
// CSRF 보호 기능 비활성화 (개발/테스트용. 실서비스에서는 활성화 권장)
http.csrf(configure -> configure.disable());
// 폼 로그인 방식 설정
http.formLogin(form -> form
.loginPage("/login-form") // 로그인 페이지 URL (GET). 사용자가 인증 안 됐을 때 여기로 이동함
.loginProcessingUrl("/login") // 로그인 처리 URL (POST). 컨트롤러 없이도 Spring Security가 자동으로 인증 처리
.defaultSuccessUrl("/main") // 로그인 성공 후 이동할 기본 페이지
);
// 요청 URL별 인가 설정
http.authorizeHttpRequests(
authorize -> authorize
.requestMatchers("/main").authenticated() // 로그인만 되어 있으면 접근 가능
.requestMatchers("/user/**").hasRole("USER") // USER 권한 있어야 접근 가능
.requestMatchers("/admin/**").hasRole("ADMIN") // ADMIN 권한 있어야 접근 가능
.anyRequest().permitAll() // 그 외 모든 요청은 인증 없이 접근 허용
);
return http.build(); // 구성된 보안 필터 체인 객체를 반환
}
}
SecurityFilterChain을 재정의했다 → Spring Security의 기본 필터 체인을 작성한 코드로 덮어쓴 것이고, → HttpSecurity를 사용해서 필터의 **행동 방식(인증, 인가, 로그인 방식 등)**을 하나하나 세밀하게 조정한 것임.
1. 스프링 시큐리티란?
Spring Security는 스프링 기반 웹 애플리케이션의 인증(Authentication)과 인가(Authorization)를 처리하는 보안 프레임워크다.
주요 기능:
- 로그인(인증) 처리
- 권한(인가) 체크
- 세션 관리
- CSRF/XSS 방어
- 다양한 인증방식 지원: Form Login, HTTP Basic, JWT, OAuth2 등
🔐 인증 vs 인가
개념 | 설명 |
인증 (Authentication) | "너 누구야?" → 로그인 검증 |
인가 (Authorization) | "이 기능 써도 돼?" → 권한 체크 |
2. 스프링 시큐리티 필터 체인
요청이 들어오면 DispatcherServlet 이전에 Spring Security의 필터 체인이 먼저 실행됨.
(실제로는 서블릿 필터 다음에 DelegatingFilterProxy가 SecurityFilterChain을 호출함)
🔄 필터 체인 구조
[사용자 요청]
↓
[서블릿 필터]
↓
[DelegatingFilterProxy]
↓
[SecurityFilterChain]
├─ UsernamePasswordAuthenticationFilter
├─ BasicAuthenticationFilter
├─ ExceptionTranslationFilter
├─ FilterSecurityInterceptor
└─ ...
필터는 순차적으로 실행되며, 인증/인가 처리, 예외 처리 등을 담당함.
3. 프록시 패턴과 Spring Security
Spring Security는 내부적으로 프록시 패턴을 활용함.
→
UserDetails
, Authentication
, SecurityContext
등을 가짜로 감싸서 동작을 위임함예시:
SecurityContextHolder.getContext().getAuthentication()
→ 실제 로그인된 사용자 정보를 꺼내는 방식도 프록시 기반으로 동작
참고 강의: 프록시 패턴 설명 유튜브
4. 인증과 인가 로직 (Form Login 흐름)
🔑 Form Login 흐름 요약
scss
복사편집
[POST /login 요청]
↓
[UsernamePasswordAuthenticationFilter]
↓ (성공 시)
[SecurityContextHolder.setAuthentication()]
↓
[세션 저장]
- 인증 실패 시 → 다시
/login-form
으로 이동
- 인증 성공 시 →
Authentication
객체가 세션에 저장됨
폼 로그인을 사용하는 경우 UsernamePasswordAuthenticationFilter가 동작함HTTP Basic 인증을 사용할 경우BasicAuthenticationFilter
가 동작 (동시에 둘 다 사용 불가)
5. 주요 필터 종류 정리
필터명 | 언제 작동? | 무엇을 하는가? |
UsernamePasswordAuthenticationFilter | 로그인(form login) 요청 ( /login 등)일 때 작동 | 사용자의 아이디/비밀번호를 추출하여 AuthenticationManager 를 통해 인증 수행. 인증 성공 시 SecurityContextHolder 에 저장 |
BasicAuthenticationFilter | 요청 헤더에 Authorization: Basic ... 이 있을 때 작동 | Base64로 인코딩된 사용자 정보를 디코딩하고 인증 수행 |
ExceptionTranslationFilter | 아래의 필터 중 인증/인가 예외가 발생했을 때 작동 | 인증 안된 사용자는 로그인 페이지로 redirect, 인가 실패는 403 오류 반환 |
SecurityContextHolderAwareRequestFilter | 매 요청마다 작동 | HttpServletRequest 를 시큐리티 aware 객체로 래핑해, request.isUserInRole() 등 사용 가능하게 함 |
FilterSecurityInterceptor | 컨트롤러에 진입하기 직전 | 인증된 사용자가 해당 자원에 접근할 권한이 있는지 최종 확인 (인가 핵심) |
LogoutFilter | /logout 요청일 때 작동 | 세션 종료, SecurityContext 초기화, 로그아웃 후 redirect 수행 |
SessionManagementFilter | 로그인 성공 시 또는 세션 체크 시점 | 세션 중복 로그인 제한, 세션 만료 처리 등 관리 |
6. FormLogin vs HTTP Basic
Form Login 구성 예시
java
복사편집
http.formLogin(form -> form
.loginPage("/login-form")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/main")
→ 내부적으로 동작:
1. /login-form: 로그인 페이지 2. /login (POST): 시큐리티가 가로채서 로그인 처리 3. 성공 시: /main 이동
HTTP Basic 구성 예시
http.httpBasic(); // 브라우저에서 ID/PW 팝업 뜸
→ 이 경우에는
BasicAuthenticationFilter
가 동작하고 UsernamePasswordAuthenticationFilter
는 동작 안함7. JWT 기반 로그인 (간단 요약)
JWT를 사용할 경우 세션을 사용하지 않고, 인증 정보를 직접 SecurityContext에 저장함
강제로 인증 객체 삽입하기
User user = User.builder().id(id).role(role).build();
MyUserDetails myUserDetails = new MyUserDetails(user);
Authentication authentication =
new UsernamePasswordAuthenticationToken(
myUserDetails,
myUserDetails.getPassword(),
myUserDetails.getAuthorities()
);
SecurityContextHolder.getContext().setAuthentication(authentication);
→ 이 코드를 통해 세션 없이도 인증 상태를 수동으로 주입 가능함
🔗 참고 자료
- GitHub (CSR/JWT 방식): https://github.com/codingspecialist/Springboot-Security/tree/csr-topic
✅ SecurityContextHolder
란?
한 줄 정의:
인증 객체(Authentication)를 저장하고 관리하는 ThreadLocal 기반의 보안 컨텍스트 저장소
🧠 작동 원리 요약
인증 흐름 중 이 위치에서 등장:
1. 로그인 요청 (POST /login)
↓
2. UsernamePasswordAuthenticationFilter
↓
3. 로그인 성공 시 Authentication 객체 생성
↓
✅ SecurityContextHolder.getContext().setAuthentication(authentication)
↓
4. SecurityContext가 세션에 저장됨
- 이렇게 저장된
Authentication
은 이후 모든 요청에서 다시 꺼내서 사용됨
- 꺼내는 방식:
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
→ 현재 로그인한 유저의 정보를 여기서 얻을 수 있음.
🔐 내부 구조 요약
SecurityContextHolder → SecurityContext (보안 컨텍스트) → Authentication (인증 정보) → Principal (사용자 정보) → Credentials (비밀번호) → Authorities (권한 목록)
📦 왜 ThreadLocal
기반인가?
- 사용자 요청은 스레드마다 독립적으로 처리됨
- 그래서 로그인 정보(인증 정보)를
ThreadLocal
로 담아두면
하나의 사용자 요청이 처리되는 동안 안전하게 인증 정보를 사용할 수 있음
✅ 로그인 후 인증 객체 접근 예시
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String username = authentication.getName(); // 로그인한 username
Collection<? extends GrantedAuthority> roles = authentication.getAuthorities();
📌 한 줄 요약
이름 | 역할 | 비고 |
SecurityContextHolder | 인증 정보를 담는 글로벌 저장소 | ThreadLocal 기반 |
SecurityContext | 실제 인증 정보(Authentication)를 담고 있음 | 세션과 연결됨 |
Authentication | 로그인 사용자 정보, 권한 등을 포함함 | 인증 여부 판단 기준 |
🔄 그림으로 전체 요청 흐름 요약
[POST /login]
↓
[UsernamePasswordAuthenticationFilter]
↓
[Authentication 생성 성공]
↓
[SecurityContextHolder.setContext(인증 정보)]
↓
[세션에 SecurityContext 저장]
↓
[다음 요청부터 SecurityContextHolder.getContext()로 인증 정보 꺼냄]
🌐 전체 요청 처리 흐름 요약 (Spring MVC + Spring Security)
[사용자 요청 (URL 입력)]
↓
[WAS (Tomcat)]
↓
[Spring Security Filter Chain] ← 인증/인가 필터들
↓
[DispatcherServlet (DS)] ← 요청의 핵심 분기 처리
↓
[HandlerMapping] ← 어떤 Controller 메서드가 호출될지 결정
↓
[Controller] ← 요청 처리 시작
↓
[Service] ← 비즈니스 로직 처리
↓
[Repository] ← DB 연산 (JPA, MyBatis 등)
↓
[Database] ← 실제 데이터 저장/조회
↓
[응답 생성 → JSON / View 등]
↓
[DispatcherServlet]
↓
[WAS → 사용자에게 HTTP 응답 전송]
BasicAuthentication
매 요청(Request)마다 클라이언트가 아이디/비밀번호를
Authorization
헤더에 실어 보내고서버는 그걸 디코딩해서 인증하는 방식임.
Share article