125 lines
7.6 KiB
Markdown
125 lines
7.6 KiB
Markdown
# Express.js SSO 연동 구현 계획
|
|
|
|
이 문서는 `sso_integration_guide.md`에서 검증된 팝업 기반 SSO 인증 흐름을 Express.js 환경에 맞게 구현하기 위한 기술 계획을 상세히 설명합니다.
|
|
|
|
## 1. 프로젝트 목표
|
|
|
|
- 외부 SSO 인증을 통해 Express.js 애플리케이션에 사용자를 자동으로 로그인 및 회원가입시키는 기능을 구현합니다.
|
|
- `express-session`을 활용하여 안정적인 세션 관리 시스템을 구축합니다.
|
|
- EJS 또는 유사한 템플릿 엔진을 사용하여 로그인 상태에 따른 동적 UI를 제공합니다.
|
|
|
|
---
|
|
|
|
## 2. 핵심 로그인 플로우 (Sequence Diagram)
|
|
|
|
WordPress 구현과 거의 동일한 흐름을 따르되, 백엔드 기술 스택만 Express.js로 변경됩니다.
|
|
|
|
```mermaid
|
|
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` 객체의 존재 여부에 따라 조건부 렌더링을 구현합니다.
|
|
```html
|
|
<% 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`과 같이 정확한 경로로 토큰을 추출하도록 코드를 작성합니다.
|
|
- **느슨한 결합:** 프론트엔드는 토큰을 백엔드로 전달하는 역할만 하고, 실제 사용자 조회, 생성, 세션 관리는 모두 백엔드(미들웨어)에서 처리하여 역할을 명확히 분리합니다.
|