Spring 7기 프로젝트/일정관리 프로젝트
Spring 쿠키(Cookie)와 세션(Session) 기반의 인증/인가
JuNo_12
2025. 5. 15. 19:40
웹 애플리케이션에서 로그인 상태를 유지하고 접근 권한을 제어하는 핵심 기술인 쿠키와 세션
| 용어 | 의미 | 예시 |
| 인증 (Authentication) | "너 누구야?" 사용자가 누구인지 확인 | 이메일/비밀번호 입력 후 로그인 |
| 인가 (Authorization) | "너 이거 해도 돼?" 권한 있는지 확인 | 관리자만 글 삭제 가능 |
쿠키(Cookie)란?
- 쿠키는 브라우저(클라이언트)에 저장되는 작은 데이터 조각
- 서버가 클라이언트에게 쿠키를 내려주면, 이후 요청마다 자동으로 쿠키를 같이 전송
Set-Cookie: SESSIONID=abc123; Path=/; HttpOnly
세션(Session)이란?
- 세션은 서버에 저장되는 사용자 상태 정보
- 브라우저에서 쿠키로 전달된 세션 ID를 사용해, 서버는 해당 사용자의 상태(예: 로그인 여부)를 식별
흐름 요약:
- 클라이언트가 로그인
- 서버가 세션 ID 생성 → 메모리/DB 등에 저장
- 클라이언트에 세션 ID를 쿠키로 전달
- 이후 요청마다 서버가 해당 세션 ID로 사용자 식별
쿠키 & 세션 기반 인증 흐름
Client -> Server: 로그인 요청 (이메일 + 비밀번호)
Server -> DB: 사용자 정보 검증
Server: 세션 생성, userId 저장
Server -> Client: 쿠키로 세션 ID 전달
Client -> Server: 쿠키 포함 요청
Server: 세션 ID로 사용자 정보 확인
Server -> Client: 요청 처리 후 응답
인증/인가 절차 요약
| 단계 | 설명 |
| 1. 로그인 요청 | 사용자가 이메일/비밀번호 전송 |
| 2. 서버 검증 | DB에서 유저 검증 후, 세션 생성 |
| 3. 세션 저장 | 서버에 로그인 상태 저장 (session.setAttribute()) |
| 4. 쿠키 전달 | 세션 ID가 담긴 쿠키를 클라이언트에게 전송 |
| 5. 인증 검사 | 이후 요청 시 쿠키로 전송된 세션 ID 확인 |
| 6. 인가 처리 | 유저 권한 확인 후 작업 허용/차단 |
1. 로그인 → 세션 저장 예시 코드
@PostMapping("/login")
public ResponseEntity<String> login(@RequestBody LoginDto dto, HttpServletRequest request) {
// HttpServletRequest는 세션 생성을 위해 사용됩니다.
User user = userRepository.findByEmail(dto.getEmail())
.orElseThrow(() -> new RuntimeException("사용자 없음"));
// 이메일로 사용자 정보를 데이터베이스에서 조회합니다.
if (!user.getPassword().equals(dto.getPassword())) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("비밀번호 오류");
}
HttpSession session = request.getSession(true); // 세션 생성
session.setAttribute("userId", user.getId());
// 세션에 현재 로그인한 유저의 ID를 userId라는 이름으로 저장합니다.
// → 이후 인증된 요청에서 userId를 기준으로 사용자 식별이 가능합니다.
return ResponseEntity.ok("로그인 성공");
}
2. 인증 필터 예시 코드
public class AuthFilter implements Filter {
private static final List<String> WHITE_LIST = List.of("/login", "/register");
// 인증이 필요 없는 경로(화이트리스트) 를 지정합니다.
// 회원가입, 로그인 요청은 로그인 상태가 없어도 접근 가능해야 하므로 제외됩니다.
@Override // 필터의 핵심 로직을 작성하는 메서드입니다.
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
// 요청/응답 객체를 HttpServletRequest/HttpServletResponse로 캐스팅합니다.
String path = request.getRequestURI();
if (WHITE_LIST.contains(path)) {
chain.doFilter(request, response);
return;
} // 요청 URI가 화이트리스트에 포함되면, 인증 검사 없이 다음 필터/컨트롤러로 넘깁니다.
HttpSession session = request.getSession(false);
// 기존 세션이 있으면 가져오고, 없으면 null을 반환합니다.
if (session == null || session.getAttribute("userId") == null) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return;
} // 세션이 없거나, 세션에 userId 정보가 없다면 로그인하지 않은 상태로 간주합니다.
chain.doFilter(request, response);
} // 인증에 성공한 경우, 다음 필터나 서블릿(컨트롤러 등)으로 요청을 전달합니다.
}
왜 HttpServletRequest가 아닌 ServletRequest를 사용하는가?
Filter의 메서드는 아래처럼 생겼는데,
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
여기서 HttpServletRequest가 아닌 ServletRequest를 쓰는 이유는,
Servlet 스펙이 HTTP 외에도 다양한 프로토콜을 처리할 수 있도록 설계됐기 때문
다만 우리는 대부분 HTTP 기반 웹을 만들기 때문에,
필요할 경우 HttpServletRequest로 다운캐스팅해서 사용하는 것
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
이건 마치 **List<String> list = new ArrayList<>();**처럼,
범용성을 위해 상위 타입을 쓰고, 필요할 땐 구체 타입으로 사용하는 구조와 비슷하다.
쿠키/세션 기반 인증의 장단점
| 장점 | 단점 |
| 구현이 단순하고 직관적 | 서버가 모든 세션 상태를 저장해야 함 |
| Spring 내장 기능과 잘 통합됨 | 분산 서버(다중 인스턴스)에서는 세션 공유 필요 |
| 자동 쿠키 처리로 편리 | 브라우저 의존적 (모바일 앱 등에선 적합 X) |
마무리
- 쿠키는 세션 ID를 클라이언트에 저장해서 보내는 매개체
- 세션은 로그인 상태 정보를 서버에서 관리하는 공간
- Spring에서는 HttpSession과 Filter를 조합해 세션 기반 인증을 구현할 수 있다.