Files
sso_expressjs_demo/docs/sso_express_guide.md
2026-01-15 14:12:41 +09:00

7.6 KiB

Express.js SSO 연동 구현 계획

이 문서는 sso_integration_guide.md에서 검증된 팝업 기반 SSO 인증 흐름을 Express.js 환경에 맞게 구현하기 위한 기술 계획을 상세히 설명합니다.

1. 프로젝트 목표

  • 외부 SSO 인증을 통해 Express.js 애플리케이션에 사용자를 자동으로 로그인 및 회원가입시키는 기능을 구현합니다.
  • express-session을 활용하여 안정적인 세션 관리 시스템을 구축합니다.
  • EJS 또는 유사한 템플릿 엔진을 사용하여 로그인 상태에 따른 동적 UI를 제공합니다.

2. 핵심 로그인 플로우 (Sequence Diagram)

WordPress 구현과 거의 동일한 흐름을 따르되, 백엔드 기술 스택만 Express.js로 변경됩니다.

sequenceDiagram
    actor User
    participant Express Frontend (Browser JS)
    participant SSO Service (Popup)
    participant Express Backend (Node.js)

    User->>Express Frontend (Browser JS): "SSO 로그인" 버튼 클릭
    Express Frontend (Browser JS)->>SSO Service (Popup): window.open() 팝업 실행
    SSO Service (Popup)-->>User: 로그인 UI 표시
    User->>SSO Service (Popup): 아이디/패스워드 입력 및 로그인
    SSO Service (Popup)->>SSO Service (Popup): 인증 처리 및 JWT 생성
    SSO Service (Popup)->>Express Frontend (Browser JS): postMessage로 JWT 전송
    Note right of SSO Service (Popup): 팝업창 닫힘
    Express Frontend (Browser JS)->>Express Frontend (Browser JS): JWT 수신 후, `?token=[JWT]` 파라미터와 함께 페이지 새로고침

    Express Frontend (Browser JS)->>Express Backend (Node.js): 페이지 요청 (GET /?token=...)
    Express Backend (Node.js)->>Express Backend (Node.js): **SSO 처리 미들웨어**에서 `token` 파라미터 감지
    Express Backend (Node.js)->>Express Backend (Node.js): JWT 디코딩하여 `sub` 클레임 추출
    Express Backend (Node.js)->>Express Backend (Node.js): DB에서 `sso_sub` 값으로 사용자 조회
    alt 사용자 없음
        Express Backend (Node.js)->>Express Backend (Node.js): 신규 사용자 생성 (DB에 저장)
        Express Backend (Node.js)->>Express Backend (Node.js): `sso_sub` 메타 정보 함께 저장
    end
    Express Backend (Node.js)->>Express Backend (Node.js): **req.session**에 사용자 정보 저장
    Express Backend (Node.js)-->>Express Frontend (Browser JS): 세션 쿠키 생성 후 `token` 제거된 URL로 리다이렉트

    Express Frontend (Browser JS)->>Express Backend (Node.js): 최종 페이지 요청 (GET /)
    Express Backend (Node.js)-->>Express Frontend (Browser JS): 로그인된 페이지 렌더링
    Express Frontend (Browser JS)-->>User: 로그인 완료된 화면 표시

3. 상세 구현 계획

A. 백엔드 (Express.js)

  1. 필수 라이브러리 설치

    • express: 웹 프레임워크
    • express-session: 세션 관리를 위한 미들웨어
    • jsonwebtoken: JWT 파싱 및 검증
    • (선택) connect-redis 또는 connect-mongo: 프로덕션 환경에서의 세션 스토어
    • (선택) ORM (Sequelize, Mongoose 등) 또는 DB 드라이버 (pg, mysql2 등)
  2. 세션 미들웨어 설정 (app.js 또는 server.js)

    • express-session을 초기화하고 애플리케이션의 모든 라우트 이전에 전역 미들웨어로 등록합니다. 보안을 위해 secret 키는 환경 변수로 관리합니다.
  3. SSO 처리 미들웨어 구현 (middleware/ssoHandler.js)

    • 요청이 들어올 때마다 req.query.token이 있는지 확인하는 미들웨어를 작성합니다.
    • 토큰이 존재하면 다음 로직을 실행합니다.
      • JWT 파싱: jsonwebtoken.decode()를 사용해 토큰의 Payload를 추출합니다. (서명 검증은 verify를 사용해야 하지만, 여기서는 sub 추출이 주 목적)
      • 사용자 식별: sub 클레임을 기준으로 데이터베이스에서 사용자를 조회합니다. (User.findOne({ where: { sso_sub: decoded.sub } }))
      • 자동 회원가입: 사용자가 없으면 sub 값과 함께 신규 사용자를 생성합니다. (WordPress 교훈: email 등 부가 정보에 의존하지 않고, sub을 유일한 식별자로 사용)
      • 세션 생성: 조회 또는 생성된 사용자 정보를 req.session.user 객체에 저장합니다. (req.session.user = { id: user.id, username: user.username };)
      • 리다이렉트: res.redirect('/')를 사용하여 token 쿼리 파라미터를 URL에서 제거하고 깨끗한 페이지로 리다이렉트합니다.
    • 토큰이 없으면 next()를 호출하여 다음 미들웨어 또는 라우트로 제어를 넘깁니다.
  4. 라우트 및 뷰 렌더링

    • 메인 라우트 핸들러에서 req.session.user 객체의 존재 여부를 확인합니다.
    • 뷰를 렌더링할 때 user 객체를 전달하여, 프론트엔드에서 로그인 상태에 따라 다른 UI를 보여줄 수 있도록 합니다. (res.render('index', { user: req.session.user });)
    • 로그아웃 라우트를 만들어 req.session.destroy()를 호출하여 세션을 파기합니다.

B. 프론트엔드 (EJS 템플릿 + Client-Side JS)

  1. 동적 UI 렌더링 (views/index.ejs)

    • 백엔드에서 전달된 user 객체의 존재 여부에 따라 조건부 렌더링을 구현합니다.
    <% if (user) { %>
        <span>환영합니다, <%= user.username %>님!</span>
        <a href="/logout">로그아웃</a>
    <% } else { %>
        <button id="sso-login-btn">Baron SSO 로그인</button>
    <% } %>
    
  2. 팝업 스크립트 (public/js/sso.js)

    • WordPress 구현과 동일한 로직을 사용합니다.
    • 팝업 실행: 로그인 버튼 클릭 시 window.open으로 SSO 페이지를 팝업으로 엽니다.
    • 토큰 수신: window.addEventListener('message', ...)로 SSO 팝업이 보낸 postMessage를 수신합니다.
      • (WordPress 교훈) event.data가 단순 문자열이 아닌 { type: 'LOGIN_SUCCESS', token: '...' } 형태의 객체일 수 있으므로, event.data.token 속성을 명확히 확인하고 추출합니다.
    • 페이지 리로드: 수신한 토큰을 ?token= 쿼리 파라미터로 붙여 페이지를 새로고침합니다. 이 동작이 백엔드의 SSO 처리 미들웨어를 트리거합니다.

C. 권장 파일 구조

/my-express-app
|-- /middleware
|   |-- ssoHandler.js       # SSO 토큰 처리 미들웨어
|-- /models
|   |-- user.js             # 사용자 데이터베이스 모델
|-- /public
|   |-- /js
|   |   |-- sso.js          # 프론트엔드 팝업 스크립트
|-- /routes
|   |-- index.js            # 메인, 로그아웃 등 라우트
|-- /views
|   |-- index.ejs           # 메인 페이지 뷰
|   |-- layout.ejs          # 공통 레이아웃
|-- app.js                  # Express 앱 초기화 및 설정
|-- package.json

4. 핵심 교훈 적용

  • 사용자 식별: WordPress 구현의 교훈에 따라, JWT의 email 필드가 아닌 sub 클레임을 사용자의 고유하고 영구적인 식별자로 사용합니다.
  • 데이터 형식: postMessage로 전달되는 데이터의 구조를 명확히 인지하고, 프론트엔드에서 event.data.token과 같이 정확한 경로로 토큰을 추출하도록 코드를 작성합니다.
  • 느슨한 결합: 프론트엔드는 토큰을 백엔드로 전달하는 역할만 하고, 실제 사용자 조회, 생성, 세션 관리는 모두 백엔드(미들웨어)에서 처리하여 역할을 명확히 분리합니다.