Spring 7기 프로젝트/일정관리 프로젝트

Spring 쿠키(Cookie)와 세션(Session) 기반의 인증/인가

JuNo_12 2025. 5. 15. 19:40

웹 애플리케이션에서 로그인 상태를 유지하고 접근 권한을 제어하는 핵심 기술인 쿠키와 세션

용어 의미 예시
인증 (Authentication) "너 누구야?" 사용자가 누구인지 확인 이메일/비밀번호 입력 후 로그인
인가 (Authorization) "너 이거 해도 돼?" 권한 있는지 확인 관리자만 글 삭제 가능

 

쿠키(Cookie)란?

  • 쿠키는 브라우저(클라이언트)에 저장되는 작은 데이터 조각
  • 서버가 클라이언트에게 쿠키를 내려주면, 이후 요청마다 자동으로 쿠키를 같이 전송
Set-Cookie: SESSIONID=abc123; Path=/; HttpOnly

 

세션(Session)이란?

  • 세션은 서버에 저장되는 사용자 상태 정보
  • 브라우저에서 쿠키로 전달된 세션 ID를 사용해, 서버는 해당 사용자의 상태(예: 로그인 여부)를 식별

흐름 요약:

  1. 클라이언트가 로그인
  2. 서버가 세션 ID 생성 → 메모리/DB 등에 저장
  3. 클라이언트에 세션 ID를 쿠키로 전달
  4. 이후 요청마다 서버가 해당 세션 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를 조합해 세션 기반 인증을 구현할 수 있다.