UMC 10기 - Spring Boot 스터디 #8

정유진·2026년 5월 25일

Spring Security 적용과 회원가입 API 구현

백엔드 개발에서 인증인가는 거의 필수적으로 등장하는 개념이다.
이번 8주차에서는 Spring Security를 처음 적용하면서 회원가입 API를 구현하고,
Public API / Private API를 분리하는 작업을 진행했습니다.

처음에는 단순히 “로그인 기능을 위한 라이브러리” 정도로 생각했지만, 이번 워크북 개념을 공부하고 미션에서 적용해보니 요청이 Security Filter Chain을 거치며 인증과 인가가 처리되는 구조를 이해하는 과정이 중요하다는 걸 느꼈습니다.

이번 글에서는

  • Spring Security 기본 개념
  • 인증(Authentication)과 인가(Authorization)
  • Stateful vs Stateless
  • 회원가입 API 구현
  • Public / Private API 분리
  • Security 예외 처리

를 중심으로 정리해보려고 합니다.




1. Spring Security란?

Spring Security는
자바 기반 웹 애플리케이션에서 인증(Authentication)인가(Authorization)를 처리하는
보안 프레임워크이다.

Spring 애플리케이션의 요청은 DispatcherServlet에 바로 전달되지 않고,
먼저 Spring Security Filter Chain을 거치게 된다.

이를 통해:

  • 로그인 여부 확인
  • 권한 검사
  • 세션 관리
  • CSRF 방어
  • 비밀번호 암호화

등의 보안 기능을 처리할 수 있다.


2. 인증(Authentication) vs 인가(Authorization)

Authentication (인증)

인증(Authentication)은 사용자가 누구인지 확인하는 과정이다.

예를 들어:

  • 이메일 + 비밀번호 로그인
  • JWT 토큰 검증
  • 세션 로그인

등이 인증 과정에 해당한다.

Spring Security에서는 사용자가 로그인 요청을 보내면:

UsernamePasswordAuthenticationFilter
AuthenticationManager
UserDetailsService

등을 통해 인증을 수행한다.

이번 미션에서는

  1. 회원가입 시 email/password 저장
  2. BCrypt 기반 비밀번호 암호화

를 구현했다.


Authorization (인가)

인가(Authorization)는 인증된 사용자가 특정 리소스에 접근할 권한이 있는지 확인하는 과정이다.

예를 들어:

  • 로그인 사용자만 접근 가능
  • ADMIN만 접근 가능
    등의 권한 제어가 인가에 해당한다.

Spring Security에서는:

.requestMatchers("/api/v1/members/signup").permitAll()
.anyRequest().authenticated()

처럼 접근 권한을 설정할 수 있다.

이번 미션에서는

  1. 회원가입 API → Public API
  2. 그 외 API → Private API

로 분리하여 인증 여부에 따라 접근을 제어했다.


3. Stateful vs Stateless


Stateful

Stateful 방식은 서버가 사용자 상태(State)를 저장하는 방식이다.

★ 대표적으로 Session 기반 인증 방식이 있다.

사용자가 로그인하면 서버는 세션(Session)을 생성하고 사용자 정보를 저장한다.
이후 클라이언트는 세션 ID를 쿠키에 담아 요청을 보내며, 서버는 세션 정보를 통해 로그인 상태를 확인한다.

특징

  • 서버가 로그인 상태를 저장
  • 세션 저장소 필요
  • 로그아웃 처리 용이
  • 서버 확장 시 세션 공유 문제 발생 가능

이번 미션에서 사용한 formLogin 방식이 Stateful 방식에 해당한다.


Stateless

Stateless 방식은 서버가 사용자 상태를 저장하지 않는 방식이다.

★ 대표적으로 JWT 기반 인증 방식이 있다.

로그인 이후 서버는 JWT 토큰을 발급하고, 클라이언트는 이후 요청마다 토큰을 함께 전송한다.
서버는 토큰만 검증하여 사용자를 식별한다.

특징

  • 서버가 상태를 저장하지 않음
  • 세션 저장소 불필요
  • 확장성에 유리
  • REST API 서버에서 많이 사용

4. Spring Security 동작 구조

Spring Security는 요청이 들어오면 먼저 Security Filter Chain에서 인증과 인가를 처리한다.

사용자가 로그인 요청을 보내면

  1. Filter가 요청을 가로채고
  2. AuthenticationManager가 인증을 수행하며
  3. UserDetailsService를 통해 사용자 정보를 조회한다.

인증이 완료되면 Authentication 객체가 생성되고, SecurityContext에 저장된다.
이후 인가 과정에서 사용자의 권한(Role)을 검사하여 접근 가능 여부를 판단한다.


5. 회원가입 API 구현

이번 미션에서는 회원가입 API를 구현했다.

회원가입 시:

  • email
  • password
  • 이름
  • 주소
  • 전화번호

등의 정보를 저장하도록 구성했다.

Member 엔티티

@Column(unique = true, nullable = false)
private String email;

@Column(nullable = false)
private String password;

이메일은 중복되지 않도록 unique 제약을 추가했다.

비밀번호 암호화

비밀번호는 BCryptPasswordEncoder를 사용하여 암호화 후 저장했다.

passwordEncoder.encode(request.getPassword())

DB에는 아래와 같은 형태로 저장된다.

2a$10...

이를 통해 비밀번호를 평문으로 저장하지 않도록 처리했다.

회원가입 API

@PostMapping("/signup")
public ApiResponse<MemberResDTO.SignupDTO> signup(
        @RequestBody MemberReqDTO.SignupDTO request
) {
    return ApiResponse.onSuccess(
            memberService.signup(request)
    );
}

6. Public API / Private API 분리

Spring Security에서는 permitAll()authenticated()를 사용하여 접근 권한을 설정할 수 있다.

.authorizeHttpRequests(requests -> requests
        .requestMatchers(allowUris).permitAll()
        .anyRequest().authenticated()
)

Public API : 회원가입 API & Swagger 관련 경로
→ 로그인 없이 접근 가능

Private API : 그 외 API 전부
→ 로그인 필요


7. Security 예외 처리

초기에는 인증되지 않은 사용자가 Private API에 접근하면 Spring Security 기본 로그인 HTML 페이지가 반환되었다.

하지만 API 서버에서는 HTML 대신 JSON 응답이 필요하기 때문에

AuthenticationEntryPoint
AccessDeniedHandler

를 구현하여 예외 응답을 통일했다.

인증 실패 처리 (401)

{
  "isSuccess": false,
  "code": "AUTH401",
  "message": "로그인이 필요합니다."
}



이번 주차에서 배운 스프링 시큐리티는 실습으로 단순히 회원가입 기능을 구현하는 것보다,
Spring Security가 요청을 어떻게 처리하는지 흐름을 이해하는 과정이 더 중요하게 느껴졌다.
그치만 항상 어렵다

특히

  • permitAll()
  • authenticated()
  • AuthenticationEntryPoint
  • AccessDeniedHandler

를 직접 적용해보면서 인증과 인가의 차이를 조금 더 명확하게 이해할 수 있었다.

아직은 formLogin 기반의 Stateful 방식만 적용했지만, 이후 JWT 기반 Stateless 인증 구조까지 연결해보면 Spring Security 흐름이 더 명확해질 것 같다.




profile
개발전공 대학생

0개의 댓글