카테고리 없음

Spring Security의 인증과 인가

com.oryneogury 2026. 1. 5. 10:06

Spring Security 인증과 인가

핵심 개념

인증(Authentication) = "너 누구야?"

로그인, 토큰 확인, 신분 확인 등 사용자가 누구인지 확인하는 과정이다.

인가(Authorization) = "너 이거 할 수 있어?"

권한 확인, 접근 제어 등 사용자가 특정 작업을 할 수 있는지 확인하는 과정이다.

쉬운 비유

  • 인증: 놀이공원 입구에서 티켓 확인
  • 인가: 각 놀이기구마다 키 제한, VIP 전용 확인

Spring Security 동작 흐름

사용자 요청
    ↓
Spring Security 필터 체인
    ↓
인증 확인 → 실패시 401
    ↓
권한 확인 → 실패시 403
    ↓
컨트롤러 실행

필터 체인이란

컨트롤러에 도달하기 전에 거치는 검문소다. 여러 필터가 순서대로 요청을 검사한다.\


차이점

1) 인증 -> 인가로 이어질 수 있지만 인가 -> 인증으로는 이어질 수 없습니다.

2) 인증은 권한 부여 결정의 일부 요소로 사용될 수 있습니다.

3) 권한 부여로 인증을 하기에는 유용하지 않을 수 있습니다.

 

- 예시를 들어보겠습니다. 비행기에 탑승하기 위해 신원을 증명하는 여권을 보여준 뒤 탑승 수속을 위한 비행기 티켓까지 보여주어야 탑승을 완료할 수 있습니다. 이처럼 신원 확인 이후 특정 권한을 얻기 위한 과정으로는 매끄럽게 이어질 수 있지만 반대로 비행기 티켓만 보유하고 있는 경우 탑승자 본인임을 증명할 수 없기 때문에 수속을 정상적으로 완료할 수 없게 됩니다.




401 vs 403

에러 의미 상황 예시
401 Unauthorized 로그인 안 함 로그인 없이 마이페이지 접근
403 Forbidden 권한 부족 일반 회원이 관리자 페이지 접근

핵심: 401은 인증 실패, 403은 인가 실패다.


권한 구조

Spring Security에서는 ROLE_ 접두사를 붙여 권한을 표현한다.

권한 설명
ROLE_USER 일반 회원
ROLE_ADMIN 관리자
ROLE_MANAGER 매니저

세션 방식 vs JWT 방식

세션 방식

서버가 로그인 정보를 기억한다.

  1. 로그인 → 서버에 세션 생성
  2. 브라우저는 세션 ID만 쿠키로 저장
  3. 다음 요청시 세션 ID로 사용자 확인

장점: 강제 로그아웃 가능
단점: 서버 메모리 사용, 여러 서버 운영시 세션 공유 필요

JWT 방식

토큰에 모든 정보를 담는다.

  1. 로그인 → 서버가 JWT 토큰 발급
  2. 브라우저는 토큰 저장
  3. 다음 요청시 토큰을 헤더에 포함

장점: 서버 부담 적음, 확장성 좋음
단점: 강제 로그아웃 어려움, 토큰 탈취 위험

언제 뭘 쓸까

상황 추천 방식
일반 웹사이트 세션
모바일 앱, API 서버 JWT
여러 서버 운영 JWT
강제 로그아웃 필요 세션

실제 설정

Spring Security는 설정 클래스에서 보안 규칙을 정의한다.

@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) {
    return http
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/public/**").permitAll()
            .requestMatchers("/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated()
        )
        .build();
}

설정 의미

  • permitAll(): 모두 접근 가능 (로그인 불필요)
  • hasRole("ADMIN"): ADMIN 권한 필요
  • authenticated(): 로그인 필요
  • anyRequest(): 위에서 지정 안 한 모든 요청 (마지막에 작성)

주의사항

1. 순서가 중요하다

// ❌ 틀림: anyRequest()를 먼저 쓰면 뒤의 설정이 무시됨
.anyRequest().authenticated()
.requestMatchers("/public/**").permitAll()

// ✅ 맞음: 구체적인 규칙을 먼저, anyRequest()는 마지막
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()

2. ROLE_ 접두사

// ❌ 틀림: ROLE_ROLE_ADMIN으로 인식됨
.hasRole("ROLE_ADMIN")

// ✅ 맞음: ROLE_는 자동으로 붙음
.hasRole("ADMIN")

3. 로그인 페이지는 열어둬야 한다

// 로그인 페이지를 permitAll()로 열어두지 않으면
// 로그인 자체가 불가능하다
.requestMatchers("/login").permitAll()

실전 예시

쇼핑몰

/ (메인)              → 모두 접근 가능
/products (상품)      → 모두 접근 가능
/cart (장바구니)      → 로그인 필요
/mypage (마이페이지)  → 로그인 필요
/admin (관리자)       → ADMIN 권한 필요

커뮤니티

/ (메인)              → 모두 접근 가능
/posts (게시글 보기)  → 모두 접근 가능
/posts/write (글쓰기) → 로그인 필요
/posts/delete (삭제)  → ADMIN 권한 필요

핵심 정리

1. 인증 vs 인가

구분 의미 실패시
인증 신원 확인 401
인가 권한 확인 403

2. 로그인 방식

방식 특징 추천 상황
세션 서버가 정보 저장 일반 웹사이트
JWT 토큰에 정보 포함 API, 모바일 앱

3. 설정 순서

  1. 구체적인 경로 먼저 (permitAll(), hasRole())
  2. anyRequest()는 무조건 마지막
  3. 로그인 페이지는 permitAll() 필수

4. 기억할 메서드

  • permitAll(): 모두 허용
  • authenticated(): 로그인 필요
  • hasRole(): 특정 권한 필요
  • anyRequest(): 나머지 모두

동작 흐름 다시 보기

1. 요청 들어옴
   ↓
2. Security 필터 체인 실행
   ↓
3. 인증 정보 확인
   - 없으면 → 401
   - 있으면 → 다음 단계
   ↓
4. 권한 확인
   - 부족하면 → 403
   - 충분하면 → 다음 단계
   ↓
5. 컨트롤러 실행
   ↓
6. 응답 반환

Spring Security는 이 모든 과정을 필터 체인에서 자동으로 처리한다. 개발자는 설정만 하면 된다.