Skip to content
스토브
마지막 업데이트

웹 서비스 세션 최적화

이해하기


세션 연동 최적화는 SUAT(Security User Access Token) 인증 토큰의 유효성 검증을 매 요청·액션마다 반복하지 않도록, 최근 검증 결과를 캐시에 저장해 재사용하는 기능이에요. 최초 진입에서 Accounts 인증 API(/auth/v5/user_token/check)로 SUAT를 검증한 뒤 결과를 캐시에 저장하고, 이후 같은 사용자의 요청에서는 캐시가 유효하면 인증 API 호출을 생략해요. 인증 API 호출을 최소화하면서도 최신 인증 상태를 유지할 수 있어요.

연동 방식은 렌더링 환경에 따라 두 가지로 나뉘어요. 서버에서 페이지를 렌더링하는 SSR 환경(백엔드)은 서버 측 Redis를 검증 캐시로 사용하고, 브라우저에서 화면을 렌더링하는 CSR·SPA 환경(프론트엔드)은 Session Storage를 검증 캐시로 사용해요.

적용 환경

캐시 저장소와 키만 다를 뿐 검증 API와 목적은 동일해요. 서비스의 렌더링 방식에 맞는 트랙을 선택하면 돼요.

구분 SSR (백엔드) CSR (프론트엔드)
렌더링 위치 서버에서 페이지 렌더링 브라우저에서 화면 렌더링
대표 환경 Spring 기반 SSR 서비스 SPA(Client-side Routing) 서비스
검증 캐시 저장소 Redis Session Storage
캐시 키 SUAT 기반 안전한 키 (예: SUAT_CHECK:{SUAT_HASH}) STOVE_USER_TOKEN_CHECK
캐시 TTL 300초(5분) 300초(5분)
검증 API /auth/v5/user_token/check /auth/v5/user_token/check

구성 요소

구성 요소 역할
Client (Browser) SUAT 쿠키 전달(SSR), 사용자 액션에 따른 토큰 검증 요청(CSR)
SSR Service (BE) 요청에서 SUAT 추출, Redis 검증 캐시 조회로 인증 API 호출 여부 결정, 페이지 렌더링
SPA Service (FE) Session Storage 검증 캐시 조회로 인증 API 호출 여부 결정, API 호출 전 공통 검증 수행
Auth API /auth/v5/user_token/check로 SUAT 유효성 검증
Redis (SSR) 최근 검증된 SUAT 결과를 TTL 동안 저장하는 서버 측 캐시
Session Storage (CSR) 검증 시각·만료 시각을 저장하는 브라우저 측 캐시

동작 원리

최초 진입 시 인증 API로 SUAT를 검증하고 결과를 캐시에 저장해요. 이후 같은 SUAT·세션의 요청에서는 캐시가 유효하면(5분 이내) 인증 API 호출을 생략하고, 캐시가 없거나 만료됐거나 SUAT가 바뀐 경우에만 재검증해요. 이렇게 동일한 SUAT에 대한 반복 검증 호출을 줄여 응답 성능을 높여요.

SSR은 서버 측 Redis에 검증 결과를 저장해 여러 요청과 다중 서버가 캐시를 공유해요. CSR은 브라우저 Session Storage에 저장해 새로고침(F5)에도 유지하되 탭을 종료하면 삭제돼요. 어느 방식이든 SUAT 원문을 캐시 키로 직접 사용하지 말고 SHA-256 등 해시값을 사용하는 것을 권장해요.

연동 가이드


사전 준비

SSR·CSR에 공통으로 필요한 준비 사항이에요. 방식별 세부 준비는 각 [개발하기] 트랙에서 안내해요.

항목 내용 비고
SUAT 인증 토큰 accounts.onstove.com/login을 통해 Client에 SUAT 인증 토큰 발급 완료 필수
인증 검증 API 연동 /auth/v5/user_token/check 호출로 SUAT 유효성을 검증할 수 있는 경로 확보 필수
검증 캐시 저장소 SSR은 Redis, CSR은 Session Storage 구성 필수
캐시 키·TTL 정책 SUAT를 식별할 안전한 키와 TTL 300초(5분) 적용. 캐시가 있으면 검증 생략, 없거나 만료 시 재검증 필수

API 접근 권한은 퍼블리싱 기술 담당자와 협의해요
인증 API 접근 권한과 환경별 도메인은 담당자를 통해 확인해 주세요. 문의: sgp_publishtech_d@smilegate.com

기본 검증 흐름

요청·액션이 발생하면 SUAT를 추출해 검증 캐시를 조회하고, 캐시가 유효하면 인증 API 호출을 생략해요. 캐시가 없거나 만료됐거나 SUAT가 바뀐 경우에만 인증 API를 호출한 뒤 결과를 캐시에 저장해요. SSR·CSR 모두 아래 판단 흐름을 따라요.

시작 전 결정 항목

서비스 연동 전에 아래 항목을 결정해요. 결정 결과에 따라 캐시 구조와 인증 실패 처리 방식이 달라져요.

결정 항목 내용
캐시 키 구조 SUAT를 식별할 안전한 키 형식 (SSR은 Redis Key, CSR은 Session Storage Key)
캐시 TTL 검증 결과 재사용 시간 (기본 300초)
인증 API 호출 방식 GET·POST 등 호출 방식과 SUAT 전달 방식
인증 성공·실패 기준 HTTP Status·업무 코드로 성공·실패를 판단하는 기준
인증 실패 처리 정책 만료·변조·미인증 구분 및 후속 처리 방식
캐시 공유 방식 (SSR) 다중 서버에서 공용 Redis 사용 여부
로그인 Redirect 정책 인증 실패 시 Redirect 또는 401 응답 처리 방식

환경 구분 안내

서비스의 렌더링 방식과 캐시 저장소 사용 가능 여부에 따라 적용 환경이 달라져요.

구분 적용 환경
SSR 적용 가능 Spring 기반 SSR 서비스, Redis 사용 가능 환경, 서버에서 SUAT Cookie 조회 가능 환경, Accounts 인증 API 호출 가능 환경
CSR 적용 가능 SPA(Client-side Routing) 서비스, Session Storage 사용 가능 환경, POST /auth/v5/user_token/check 호출 가능 환경
별도 검토 필요 Redis를 사용할 수 없는 SSR 환경, 서버·브라우저 캐시를 모두 사용할 수 없는 환경

연동 체크리스트

연동 전에 아래 항목을 확인해요.

확인 항목 내용
SUAT Cookie 이름·Domain·Path 확인
인증 API URL 및 HTTP Method 확인
인증 요청 방식 Cookie 전달 방식 확인
성공 응답 HTTP Status 및 업무 코드 확인
실패 응답 만료·변조·미인증 구분 확인
Redis (SSR) Key 구조 및 TTL 확인, 다중 서버 공용 Redis 사용 여부
Session Storage (CSR) 키·TTL 확인, 공통 검증 로직 적용 여부
로그인 처리 Redirect 또는 401 정책 확인
네트워크 인증 API 접근 권한 확인
운영 모니터링 인증 API 호출량 및 실패율 모니터링

개발하기


SSR 연동 (백엔드)

서버에서 페이지를 렌더링하는 환경의 연동이에요. 요청에 포함된 SUAT를 서버가 추출해 Redis 검증 캐시로 인증 API 호출 여부를 결정하고, 캐시가 유효하면 검증을 생략한 채 페이지를 렌더링해요.

사전 준비

  • accounts.onstove.com/login을 통해 Client에 SUAT 인증 토큰이 발급되어 있어야 해요.
  • SSR 서비스가 요청 헤더에 포함된 SUAT Cookie를 수신할 수 있어야 해요.
  • /auth/v5/user_token/check API와 연동해 SUAT 유효성을 검증할 수 있어야 해요.
  • 검증 결과를 저장할 Redis 캐시가 구성되어 있어야 하고, SUAT를 식별할 안전한 키와 TTL 300초(5분)를 사용해야 해요.
  • Redis 캐시가 있으면 인증 검증 API 호출을 생략하고, 없거나 만료된 경우에만 재검증하도록 구현해요.

개발 흐름

SSR 서비스 진입 시 Client가 보유한 SUAT로 사용자 인증을 수행해요. 검증 결과를 Redis에 캐시해 동일 SUAT의 반복 검증 호출을 줄여요.

  1. SSR 서비스 진입 시 요청 헤더에서 SUAT를 추출해요.
  2. SUAT 기반 캐시 키(예: SUAT_CHECK:{SUAT_HASH})로 Redis 검증 캐시를 조회해요.
  3. 캐시가 존재하고 유효하면 /auth/v5/user_token/check 호출 없이 요청을 처리해요.
  4. 캐시가 없거나 만료됐으면 /auth/v5/user_token/check를 호출해 SUAT를 검증해요.
  5. 검증에 성공하면 결과를 Redis에 저장하고 TTL을 300초(5분)로 설정해요.
  6. 이후 동일 SUAT 요청은 캐시를 재사용해 SSR 서비스 응답 성능을 높여요.

SUAT 원문을 Redis 키로 직접 쓰지 마세요
Redis는 SUAT 검증 결과를 일정 시간 재사용하기 위한 인증 검증 캐시예요. SUAT 원문을 키로 직접 사용하지 말고 SHA-256 등의 해시값을 사용하는 것을 권장해요.

트러블슈팅

응답 code별 처리 방안이에요. 상세 응답 코드·메시지 스펙은 API & SDK 레퍼런스 메뉴를 참고해 주세요.

HTTP Status업무 코드메시지설명
2000success성공
400400bad request잘못된 요청
500500unknown error서버 내부 오류

샘플 코드

Spring 기반 SSR 서비스에서 요청 SUAT와 캐시된 SUAT를 비교해, 값이 바뀌었을 때만 인증 API를 호출하는 예제예요. 다중 서버 환경에서는 로컬 세션 대신 공용 Redis를 캐시로 사용해 서버 간 검증 결과를 공유해 주세요.

java
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import org.springframework.http.*;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.client.RestTemplate;
import java.util.Arrays;
import java.util.Objects;

@Controller
public class MainController {

    private static final String AUTH_API =
        "https://accounts.onstove.com/auth/v5/user_token/check";

    private final RestTemplate restTemplate = new RestTemplate();

    @GetMapping("/main")
    public String main(HttpServletRequest request) {
        HttpSession session = request.getSession();
        // 검증 캐시 유효 시간 5분(300초)
        session.setMaxInactiveInterval(300);

        // 1. 요청 Cookie에서 SUAT 추출
        String requestSuat = Arrays.stream(request.getCookies())
            .filter(cookie -> "SUAT".equals(cookie.getName()))
            .map(Cookie::getValue)
            .findFirst()
            .orElse(null);

        // 2. 캐시에 저장된 SUAT 조회
        String sessionSuat = (String) session.getAttribute("SUAT");

        // 3. SUAT가 바뀌었거나 캐시가 없으면 인증 API 호출
        if (!Objects.equals(requestSuat, sessionSuat)) {
            HttpHeaders headers = new HttpHeaders();
            headers.add(HttpHeaders.COOKIE, "SUAT=" + requestSuat);
            HttpEntity<Void> entity = new HttpEntity<>(headers);
            ResponseEntity<String> response = restTemplate.exchange(
                AUTH_API,
                HttpMethod.GET,
                entity,
                String.class);
            if (!response.getStatusCode().is2xxSuccessful()) {
                throw new RuntimeException("Invalid SUAT");
            }
            // 4. 검증 성공 시 SUAT를 캐시에 저장
            session.setAttribute("SUAT", requestSuat);
        }
        // 5. 페이지 렌더링
        return "main";
    }
}

CSR 연동 (프론트엔드)

브라우저에서 화면을 렌더링하는 SPA 환경의 연동이에요. Session Storage 검증 캐시로 인증 API 호출 여부를 결정하고, 캐시가 유효하면 검증을 생략한 채 요청을 처리해요.

사전 준비

  • accounts.onstove.com/login을 통해 SUAT 인증 토큰이 발급되어 있어야 해요.
  • SPA 서비스가 POST /auth/v5/user_token/check API로 사용자 토큰 유효성을 검증할 수 있어야 해요.
  • 검증 결과를 저장할 Session Storage를 사용할 수 있어야 해요.
  • Session Storage에 STOVE_USER_TOKEN_CHECK 키로 검증 캐시를 저장하고 TTL 300초(5분)로 관리해요.
  • 모든 API 호출은 검증 캐시를 확인하는 공통 로직(Interceptor 또는 API Wrapper)을 통해 처리하는 것을 권장해요.

개발 흐름

서비스 최초 진입과 사용자 액션마다 Session Storage의 검증 캐시를 확인해요. 캐시가 유효하면 인증 API 호출을 생략하고, 새로고침(F5)에도 캐시가 유지돼요.

  1. 서비스 최초 진입 시 POST /auth/v5/user_token/check로 사용자 토큰 유효성을 검증해요.
  2. 검증이 완료되면 Session Storage(STOVE_USER_TOKEN_CHECK)에 검증 시각(verifiedAt)과 만료 시각(expireAt)을 저장해요.
  3. 사용자 액션으로 API를 호출하기 전에 Session Storage의 검증 캐시를 확인해요.
  4. 캐시가 유효하면(5분 이내) 인증 API 호출을 생략하고 요청을 처리해요.
  5. 캐시가 만료됐거나 없으면 인증 API를 다시 호출해 검증한 뒤 Session Storage를 갱신해요.
  6. 브라우저 새로고침(F5) 시에도 Session Storage가 유지되므로, 캐시가 유효하면 재검증하지 않아요.

Session Storage 캐시는 새로고침에는 유지되고 탭 종료 시 삭제돼요
STOVE_USER_TOKEN_CHECK 키에 검증 시각(verifiedAt)과 만료 시각(expireAt)을 저장해요. verifiedAt부터 5분간 유효하며 expireAt 이후에는 재검증이 필요해요. 새로고침(F5) 시에도 유지되지만 브라우저(탭)를 종료하면 삭제돼요.

트러블슈팅

응답 code별 처리 방안이에요. 상세 응답 코드·메시지 스펙은 API & SDK 레퍼런스 메뉴를 참고해 주세요.

HTTP Status업무 코드메시지설명
2000success성공
400400bad request잘못된 요청
500500unknown error서버 내부 오류

샘플 코드

Session Storage 검증 캐시를 확인해 유효하면 인증 API 호출을 생략하고, API 호출 전 공통 래퍼로 토큰 검증을 수행하는 예제예요.

js
const STORAGE_KEY = "STOVE_USER_TOKEN_CHECK";
const CACHE_TTL = 5 * 60 * 1000; // 5분

/**
 * 토큰 유효성 검증. 캐시가 유효하면 API 호출을 생략해요.
 */
async function validateUserToken() {
    const cache = getTokenCheckCache();

    // 캐시가 유효하면 검증 API 호출 생략
    if (cache && cache.expireAt > Date.now()) {
        console.log("Skip /auth/v5/user_token/check");
        return true;
    }

    // 캐시가 없거나 만료 시 검증 API 호출
    const response = await fetch("/auth/v5/user_token/check", {
        method: "POST",
        credentials: "include"
    });

    if (!response.ok) {
        throw new Error("Invalid User Token");
    }

    saveTokenCheckCache();
    return true;
}

/**
 * 검증 결과를 Session Storage에 저장
 */
function saveTokenCheckCache() {
    const now = Date.now();
    sessionStorage.setItem(
        STORAGE_KEY,
        JSON.stringify({
            verifiedAt: now,
            expireAt: now + CACHE_TTL
        })
    );
}

/**
 * Session Storage에서 검증 캐시 조회
 */
function getTokenCheckCache() {
    const value = sessionStorage.getItem(STORAGE_KEY);
    if (!value) {
        return null;
    }
    try {
        return JSON.parse(value);
    } catch {
        sessionStorage.removeItem(STORAGE_KEY);
        return null;
    }
}

/**
 * API 호출 전 토큰 검증을 수행하는 공통 래퍼
 */
async function requestApi() {
    await validateUserToken();
    return fetch("/api/example", {
        credentials: "include"
    });
}

자주 묻는 질문



Q. SSR 방식과 CSR 방식은 어떻게 다른가요?
A. 서버에서 페이지를 렌더링하는 SSR은 Redis에 검증 결과를 저장해 여러 요청과 다중 서버가 캐시를 공유해요. 브라우저에서 렌더링하는 CSR(SPA)은 Session Storage에 저장해 새로고침에는 유지되지만 탭 종료 시 삭제돼요.
두 방식 모두 /auth/v5/user_token/check 호출을 최소화한다는 목적은 같아요.
Q. 캐시 TTL은 왜 300초(5분)인가요?
A. 인증 상태의 최신성과 API 호출 절감 사이의 균형을 위한 기본값이에요. verifiedAt부터 5분간 검증 결과를 재사용하고, 만료 후에는 다시 검증해요. 서비스 정책에 따라 조정할 수 있어요.
Q. 캐시가 유효해도 인증 API를 다시 호출해야 하는 경우가 있나요?
A. 사용자가 재로그인했거나 SUAT가 갱신된 경우, 캐시가 만료·삭제된 경우에는 다시 호출해요. SSR은 요청 SUAT와 캐시 SUAT가 다르면 재검증하고, CSR은 expireAt이 지나면 재검증해요.
Q. SUAT를 캐시 키로 그대로 사용해도 되나요?
A. 권장하지 않아요. SUAT 원문을 키로 직접 사용하면 민감한 토큰이 노출될 수 있어요. SSR의 Redis Key는 SHA-256 등 해시값을 사용해 주세요.
Q. 다중 서버 환경에서는 캐시를 어떻게 공유하나요?
A. SSR은 서버별 로컬 세션 대신 공용 Redis를 사용해 여러 서버가 같은 검증 캐시를 공유하도록 구성하는 것을 권장해요. 로컬 세션만 사용하면 서버마다 캐시가 달라 인증 API 호출이 늘어요.
Q. SPA에서 매 API 호출마다 검증 로직을 넣어야 하나요?
A. 개별 호출마다 넣기보다 Interceptor 또는 API Wrapper 같은 공통 로직으로 처리하는 것을 권장해요. 모든 API 호출이 같은 검증 캐시 확인 절차를 거치게 돼요.
Q. 상세 응답 코드는 어디서 확인하나요?
A. 엔드포인트별 상세 응답 코드·메시지 스펙은 API & SDK 레퍼런스 메뉴에서 제공돼요. 이 가이드의 트러블슈팅 표는 대표 코드(200/400/500)만 안내해요.