# Synology SSO 연동 작업계획서 > 작성일: 2026-01-10 > 예상 기간: 2~3일 > 우선순위: 5 > 선행 작업: 4번 (Gmail OAuth 로그인) --- ## 1. 기능 개요 ### 1.1 핵심 컨셉 - 사내 Synology NAS의 SSO Server를 통한 로그인 - **4번(Gmail OAuth)과 동일한 구조**로 구현 - Google OAuth와 병행 사용 가능 (사용자 선택) - Synology 계정 이메일로 기존 사용자 매칭 ### 1.2 로그인 페이지 ``` ┌─────────────────────────────────────────────────────────────────┐ │ │ │ 📊 주간보고 시스템 │ │ │ │ ┌─────────────────────────────────────┐ │ │ │ [G] Google로 로그인 │ │ │ └─────────────────────────────────────┘ │ │ ┌─────────────────────────────────────┐ │ │ │ [S] Synology로 로그인 │ │ ← 이번 작업 │ └─────────────────────────────────────┘ │ │ │ │ ─────────────── 또는 ─────────────── │ │ │ │ 이메일: [_________________________] │ │ 비밀번호: [_________________________] │ │ │ │ [로그인] [비밀번호 찾기] │ │ │ └─────────────────────────────────────────────────────────────────┘ ``` ### 1.3 Synology SSO 로그인 플로우 ``` [Synology로 로그인] 클릭 ↓ Synology SSO Server OAuth 인증 ↓ Synology 계정 이메일 획득 ↓ wr_employee_info.email 매칭? ├─ NO → "등록되지 않은 사용자입니다. 관리자에게 문의하세요." └─ YES ↓ 비밀번호 설정됨? ├─ YES → 메인 페이지로 이동 └─ NO → 비밀번호 설정 페이지 "비상시 로그인을 위해 비밀번호를 설정해주세요" ``` ### 1.4 결정 사항 | # | 항목 | 결정 | |:-:|------|:----:| | 1 | 매칭 기준 | Synology 계정 이메일 ↔ wr_employee_info.email | | 2 | 매칭 안됨 | 로그인 거부, 관리자 문의 안내 | | 3 | 비밀번호 미설정 | 4번과 동일하게 설정 유도 | | 4 | Google/Synology 동시 연결 | 허용 (1인 1계정씩) | --- ## 2. Synology SSO Server 개요 ### 2.1 SSO Server란? - Synology NAS에서 제공하는 OAuth 2.0 기반 인증 서버 - DSM (DiskStation Manager) 패키지로 설치 - 사내 NAS 계정으로 외부 애플리케이션 로그인 가능 ### 2.2 OAuth 2.0 흐름 (Google과 동일) ``` 1. 사용자 → [Synology로 로그인] 클릭 2. 서버 → Synology SSO 인증 페이지로 리다이렉트 3. 사용자 → Synology 계정 로그인, 권한 승인 4. Synology → 콜백 URL로 리다이렉트 (code 포함) 5. 서버 → code로 access_token 요청 6. 서버 → access_token으로 사용자 정보 요청 7. 서버 → email로 wr_employee_info 조회 - 있으면: 세션 생성, 로그인 완료 - 없으면: 에러 페이지 표시 ``` --- ## 3. 데이터 모델 ### 3.1 사용자 테이블 수정 (wr_employee_info) ```sql -- 4번 작업에서 추가한 컬럼에 Synology 관련 컬럼 추가 ALTER TABLE wr_employee_info ADD COLUMN synology_id VARCHAR(100), -- Synology 고유 ID ADD COLUMN synology_username VARCHAR(100), -- Synology 사용자명 ADD COLUMN synology_linked_at TIMESTAMP; -- Synology 연결 일시 -- 인덱스 CREATE UNIQUE INDEX idx_employee_synology_id ON wr_employee_info(synology_id) WHERE synology_id IS NOT NULL; ``` ### 3.2 최종 사용자 테이블 구조 (4번 + 5번) ```sql -- wr_employee_info 인증 관련 컬럼 요약 employee_id SERIAL PRIMARY KEY, ... -- 비밀번호 (4번) password_hash VARCHAR(200), -- Google OAuth (4번) google_id VARCHAR(100), google_email VARCHAR(100), google_linked_at TIMESTAMP, -- Synology SSO (5번) synology_id VARCHAR(100), synology_username VARCHAR(100), synology_linked_at TIMESTAMP, -- 공통 last_login_at TIMESTAMP, last_login_ip VARCHAR(50), last_login_type VARCHAR(20), -- PASSWORD, GOOGLE, SYNOLOGY ... ``` --- ## 4. API 설계 ### 4.1 Synology SSO API | Method | Endpoint | 설명 | |--------|----------|------| | GET | /api/auth/synology | Synology OAuth 시작 (리다이렉트) | | GET | /api/auth/synology/callback | Synology 콜백 처리 | ### 4.2 기존 API와 통합 | Method | Endpoint | 설명 | 비고 | |--------|----------|------|------| | GET | /api/auth/me | 현재 사용자 정보 | login_type 포함 | | POST | /api/auth/logout | 로그아웃 | 공통 | --- ## 5. Synology SSO Server 설정 가이드 ### 5.1 SSO Server 패키지 설치 1. **DSM 접속**: `https://nas.company.com:5001` 관리자 계정으로 로그인 2. **패키지 센터** 열기 3. **"SSO Server"** 검색 → **설치** 4. 설치 완료 후 **열기** ``` 패키지 센터 > 검색: "SSO Server" > [설치] ``` ### 5.2 SSO Server 기본 설정 1. **SSO Server** 앱 열기 2. **설정** 탭 진입 3. 기본 설정 확인: | 설정 항목 | 권장 값 | |----------|---------| | SSO 서비스 활성화 | ✅ 체크 | | HTTPS 사용 | ✅ 체크 (필수) | | 포트 | 5001 (기본값) | ### 5.3 애플리케이션 등록 1. **SSO Server** > **애플리케이션** 탭 2. **[추가]** 버튼 클릭 3. 아래 정보 입력: ``` ┌─────────────────────────────────────────────────────────────────┐ │ 애플리케이션 추가 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ 애플리케이션 이름: [주간보고시스템________________] │ │ │ │ 리디렉션 URI: │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ https://weeklyreport.company.com/api/auth/synology/callback │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ │ ※ 개발용 추가 (선택): │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ http://localhost:3000/api/auth/synology/callback │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ │ [저장] │ └─────────────────────────────────────────────────────────────────┘ ``` 4. **저장** 후 **Client ID / Client Secret** 확인 및 복사 ``` ┌─────────────────────────────────────────────────────────────────┐ │ 애플리케이션 정보 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ 애플리케이션 이름: 주간보고시스템 │ │ │ │ Client ID: abc123def456... [복사] │ │ Client Secret: xyz789ghi012... [복사] │ │ │ │ ※ Client Secret은 다시 볼 수 없으니 반드시 복사해두세요! │ │ │ └─────────────────────────────────────────────────────────────────┘ ``` ### 5.4 사용자 권한 설정 1. **SSO Server** > **권한** 탭 2. 로그인 허용할 사용자/그룹 선택 ``` ┌─────────────────────────────────────────────────────────────────┐ │ 권한 설정 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ 애플리케이션: 주간보고시스템 │ │ │ │ 허용된 사용자/그룹: │ │ ☑ administrators │ │ ☑ developers │ │ ☑ users │ │ ☐ guests │ │ │ │ ※ 또는 [모든 사용자 허용] 선택 │ │ │ └─────────────────────────────────────────────────────────────────┘ ``` ### 5.5 HTTPS/SSL 인증서 확인 **제어판 > 보안 > 인증서**에서 유효한 SSL 인증서 확인 | 확인 항목 | 필수 여부 | |----------|:--------:| | 유효한 SSL 인증서 | ✅ 필수 | | 인증서 만료일 확인 | ✅ 확인 | | Let's Encrypt 또는 정식 인증서 | 권장 | ``` ※ 자체 서명 인증서(Self-signed)는 브라우저 경고 발생할 수 있음 ※ Let's Encrypt 무료 인증서 권장 ``` ### 5.6 방화벽/포트 설정 외부에서 NAS 접근이 필요한 경우: | 포트 | 용도 | 필요 여부 | |:----:|------|:--------:| | 5001 | DSM HTTPS | ✅ 필수 | | 443 | 역방향 프록시 사용 시 | 선택 | ``` ※ 공유기/방화벽에서 5001 포트 개방 필요 ※ 또는 역방향 프록시로 443 → 5001 연결 ``` ### 5.7 설정 완료 체크리스트 | # | 항목 | 확인 | |:-:|------|:----:| | 1 | SSO Server 패키지 설치 | ☐ | | 2 | SSO 서비스 활성화 | ☐ | | 3 | 애플리케이션 등록 (주간보고시스템) | ☐ | | 4 | Client ID 복사 | ☐ | | 5 | Client Secret 복사 | ☐ | | 6 | 리디렉션 URI 설정 (운영) | ☐ | | 7 | 리디렉션 URI 설정 (개발) - 선택 | ☐ | | 8 | 사용자/그룹 권한 설정 | ☐ | | 9 | SSL 인증서 유효 확인 | ☐ | | 10 | 외부 접근 테스트 | ☐ | ### 5.8 설정 후 .env 파일 업데이트 ```env # Synology SSO (5.3에서 복사한 값 입력) SYNOLOGY_SSO_URL=https://nas.company.com:5001 SYNOLOGY_CLIENT_ID=여기에_Client_ID_붙여넣기 SYNOLOGY_CLIENT_SECRET=여기에_Client_Secret_붙여넣기 SYNOLOGY_REDIRECT_URI=https://weeklyreport.company.com/api/auth/synology/callback ``` --- ## 6. 구현 상세 ### 6.1 Synology OAuth 엔드포인트 ``` # 인증 요청 (Authorization) GET https://{SYNOLOGY_SSO_URL}/webman/sso/SSOOauth.cgi ?response_type=code &client_id={CLIENT_ID} &redirect_uri={REDIRECT_URI} &scope=user_id # 토큰 요청 (Token) POST https://{SYNOLOGY_SSO_URL}/webman/sso/SSOAccessToken.cgi Content-Type: application/x-www-form-urlencoded grant_type=authorization_code &code={CODE} &client_id={CLIENT_ID} &client_secret={CLIENT_SECRET} &redirect_uri={REDIRECT_URI} # 사용자 정보 요청 (UserInfo) GET https://{SYNOLOGY_SSO_URL}/webman/sso/SSOUserInfo.cgi ?access_token={ACCESS_TOKEN} ``` ### 6.2 사용자 정보 응답 예시 ```json { "data": { "email": "hyosung@company.com", "user_id": 1001, "user_name": "hyosung" }, "success": true } ``` ### 6.3 API 구현 코드 (예시) ```typescript // backend/api/auth/synology.get.ts export default defineEventHandler((event) => { const config = useRuntimeConfig(); const authUrl = new URL(`${config.synologySsoUrl}/webman/sso/SSOOauth.cgi`); authUrl.searchParams.set('response_type', 'code'); authUrl.searchParams.set('client_id', config.synologyClientId); authUrl.searchParams.set('redirect_uri', config.synologyRedirectUri); authUrl.searchParams.set('scope', 'user_id'); return sendRedirect(event, authUrl.toString()); }); // backend/api/auth/synology/callback.get.ts export default defineEventHandler(async (event) => { const query = getQuery(event); const code = query.code as string; if (!code) { return sendRedirect(event, '/login?error=no_code'); } // 1. Access Token 요청 const tokenResponse = await $fetch(`${config.synologySsoUrl}/webman/sso/SSOAccessToken.cgi`, { method: 'POST', body: new URLSearchParams({ grant_type: 'authorization_code', code, client_id: config.synologyClientId, client_secret: config.synologyClientSecret, redirect_uri: config.synologyRedirectUri, }), }); // 2. 사용자 정보 요청 const userInfo = await $fetch(`${config.synologySsoUrl}/webman/sso/SSOUserInfo.cgi`, { params: { access_token: tokenResponse.access_token }, }); // 3. 이메일로 사용자 매칭 const employee = await findEmployeeByEmail(userInfo.data.email); if (!employee) { return sendRedirect(event, '/login?error=not_registered'); } // 4. Synology 정보 업데이트 await updateEmployeeSynologyInfo(employee.employee_id, { synology_id: userInfo.data.user_id, synology_username: userInfo.data.user_name, }); // 5. 세션 생성 await createSession(event, employee, 'SYNOLOGY'); // 6. 비밀번호 설정 여부 확인 if (!employee.password_hash) { return sendRedirect(event, '/auth/set-password'); } return sendRedirect(event, '/'); }); ``` --- ## 7. 화면 설계 ### 7.1 로그인 페이지 수정 (/login) 4번 작업에서 만든 로그인 페이지에 Synology 버튼 추가 ```vue ``` ### 7.2 마이페이지 수정 (/mypage) ``` ┌─────────────────────────────────────────────────────────────────┐ │ 마이페이지 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ 👤 기본 정보 │ │ ─────────────────────────────────────────────────────────────── │ │ 이름: 조효성 │ │ 이메일: hyosung@company.com │ │ ... │ │ │ │ 🔗 외부 계정 연결 │ │ ─────────────────────────────────────────────────────────────── │ │ │ │ Google: ✅ 연결됨 (hyosung@gmail.com) [연결 해제] │ │ 연결일: 2026-01-10 │ │ │ │ Synology: ✅ 연결됨 (hyosung) [연결 해제] │ │ 연결일: 2026-01-10 │ │ │ │ 🔒 비밀번호 │ │ ─────────────────────────────────────────────────────────────── │ │ ... │ │ │ │ 마지막 로그인: 2026-01-10 09:30 (Synology) │ │ │ └─────────────────────────────────────────────────────────────────┘ ``` --- ## 8. 작업 일정 ### Phase 1: Synology SSO 설정 + API (1.5일) - [ ] 시작: - [ ] 완료: - [ ] 소요시간: **작업 내용:** - [ ] Synology SSO Server 애플리케이션 등록 - [ ] wr_employee_info 컬럼 추가 (synology_id 등) - [ ] 환경 변수 설정 - [ ] Synology OAuth 시작/콜백 API - [ ] 사용자 매칭 로직 --- ### Phase 2: UI + 테스트 (1일) - [ ] 시작: - [ ] 완료: - [ ] 소요시간: **작업 내용:** - [ ] 로그인 페이지에 Synology 버튼 추가 - [ ] 마이페이지 외부 계정 연결 표시 - [ ] 로그인 이력에 login_type 기록 - [ ] 전체 플로우 테스트 --- ## 작업 완료 결과 ### Phase별 작업 시간 | Phase | 작업 내용 | 시작 | 완료 | 소요시간 | |:-----:|----------|:----:|:----:|:--------:| | 1 | Synology SSO 설정 + API | - | - | - | | 2 | UI + 테스트 | - | - | - | | | | | **총 소요시간** | **-** | --- ### 생성/수정된 파일 | 구분 | 파일 | 작업 | |------|------|:----:| | **DB** | wr_employee_info | 수정 (synology 컬럼 추가) | | **API** | backend/api/auth/synology.get.ts | 신규 | | **API** | backend/api/auth/synology/callback.get.ts | 신규 | | **Frontend** | frontend/pages/login.vue | 수정 | | **Frontend** | frontend/pages/mypage.vue | 수정 | | **Config** | .env | 수정 (Synology 설정 추가) | --- ## 9. 기술 스택 - **Backend**: Nitro (H3) + PostgreSQL - **Frontend**: Nuxt3 + Vue3 + Bootstrap 5 - **OAuth**: Synology SSO Server (OAuth 2.0) - **세션**: 기존 방식 유지 (4번과 공유) --- ## 10. 주의사항 ### 10.1 Synology SSO Server 요구사항 - DSM 7.0 이상 권장 - SSO Server 패키지 설치 필요 - HTTPS 필수 (유효한 SSL 인증서) ### 10.2 네트워크 설정 - 외부에서 Synology NAS 접근 가능해야 함 - 방화벽에서 5001 포트 (HTTPS) 허용 필요 - 또는 역방향 프록시 설정 ### 10.3 개발 환경 제약 - localhost 콜백이 안 될 수 있음 - ngrok 또는 개발용 도메인 필요할 수 있음 --- ## 11. 향후 확장 고려 1. **LDAP 연동**: Synology LDAP Server와 통합 2. **그룹 기반 권한**: Synology 그룹 → 시스템 권한 매핑 3. **자동 사용자 생성**: Synology 계정 → 자동 사용자 등록 (관리자 승인)