# Gmail OAuth 로그인 작업계획서 > 작성일: 2026-01-10 > 예상 기간: 5~7일 > 우선순위: 4 --- ## 1. 기능 개요 ### 1.1 핵심 컨셉 - **Google OAuth + 비밀번호 인증** 모두 지원 (개발/운영 동일) - Gmail 주소로 기존 사용자(wr_employee_info.email) 매칭 - 매칭 안되면 로그인 거부 → "관리자에게 문의하세요" - **OAuth 로그인 후 비밀번호 미설정 시 설정 안내** - **비밀번호 찾기**: 이름+이메일+핸드폰 매칭 → 임시 비밀번호 이메일 발송 ### 1.2 로그인 플로우 (개발/운영 동일) ``` ┌─────────────────────────────────────────────────────────────────┐ │ 로그인 페이지 │ │ │ │ [G] Google로 로그인 │ │ [S] Synology로 로그인 ← (5번 작업 후 추가) │ │ │ │ ──────────── 또는 ──────────── │ │ │ │ 이메일: [_______________] │ │ 비밀번호: [_______________] │ │ │ │ [로그인] [비밀번호 찾기] │ └─────────────────────────────────────────────────────────────────┘ ``` ### 1.3 Google OAuth 로그인 플로우 ``` [Google로 로그인] 클릭 ↓ Google OAuth 인증 ↓ Gmail 주소 획득 ↓ wr_employee_info.email 매칭? ├─ NO → "등록되지 않은 사용자입니다. 관리자에게 문의하세요." └─ YES ↓ 비밀번호 설정됨? ├─ YES → 메인 페이지로 이동 └─ NO → 비밀번호 설정 페이지 "비상시 로그인을 위해 비밀번호를 설정해주세요" ``` ### 1.4 비밀번호 찾기 플로우 ``` [비밀번호 찾기] 클릭 ↓ ┌─────────────────────────────────────┐ │ 이름: [_______________] │ │ 이메일: [_______________] │ │ 핸드폰: [_______________] │ │ │ │ [임시 비밀번호 발송] │ └─────────────────────────────────────┘ ↓ 세 가지 모두 매칭되는 사용자 확인 ├─ 매칭됨 → 이메일로 임시 비밀번호 발송 → "이메일을 확인해주세요" └─ 불일치 → "일치하는 정보가 없습니다" ``` ### 1.5 결정 사항 | # | 항목 | 결정 | |:-:|------|:----:| | 1 | 매칭 안되는 Gmail | 로그인 거부, 관리자 문의 안내 | | 2 | 비밀번호 관리 | 필수 (OAuth 로그인 후 미설정 시 설정 유도) | | 3 | Google 계정 연결 | 1인 1계정 | | 4 | 환경별 로그인 | 개발/운영 동일 (OAuth + 비밀번호 모두 지원) | | 5 | 비밀번호 찾기 | 이름+이메일+핸드폰 매칭 → 임시 비밀번호 이메일 발송 | --- ## 2. 데이터 모델 ### 2.1 사용자 테이블 수정 (wr_employee_info) ```sql -- 기존 테이블에 컬럼 추가 ALTER TABLE wr_employee_info ADD COLUMN password_hash VARCHAR(200), -- 비밀번호 해시 ADD COLUMN google_id VARCHAR(100), -- Google 고유 ID (sub) ADD COLUMN google_email VARCHAR(100), -- Google 이메일 (확인용) ADD COLUMN google_linked_at TIMESTAMP, -- Google 연결 일시 ADD COLUMN last_login_at TIMESTAMP, -- 마지막 로그인 ADD COLUMN last_login_ip VARCHAR(50); -- 마지막 로그인 IP -- 인덱스 CREATE UNIQUE INDEX idx_employee_google_id ON wr_employee_info(google_id) WHERE google_id IS NOT NULL; ``` ### 2.2 로그인 이력 테이블 (wr_login_history) - 선택 ```sql CREATE TABLE wr_login_history ( history_id SERIAL PRIMARY KEY, employee_id INTEGER NOT NULL REFERENCES wr_employee_info(employee_id), login_type VARCHAR(20) NOT NULL, -- GOOGLE, PASSWORD login_ip VARCHAR(50), user_agent VARCHAR(500), login_at TIMESTAMP DEFAULT NOW(), success BOOLEAN DEFAULT true, fail_reason VARCHAR(200) -- 실패 시 사유 ); CREATE INDEX idx_login_history_employee ON wr_login_history(employee_id); CREATE INDEX idx_login_history_at ON wr_login_history(login_at); ``` --- ## 3. API 설계 ### 3.1 인증 API | Method | Endpoint | 설명 | |--------|----------|------| | GET | /api/auth/google | Google OAuth 시작 (리다이렉트) | | GET | /api/auth/google/callback | Google 콜백 처리 | | POST | /api/auth/login | 이메일/비밀번호 로그인 | | POST | /api/auth/logout | 로그아웃 | | GET | /api/auth/me | 현재 사용자 정보 | ### 3.2 비밀번호 관리 API | Method | Endpoint | 설명 | |--------|----------|------| | POST | /api/auth/set-password | 비밀번호 최초 설정 (OAuth 후) | | PUT | /api/auth/change-password | 비밀번호 변경 (본인) | | POST | /api/auth/find-password | 비밀번호 찾기 (임시 비밀번호 발송) | | PUT | /api/admin/user/[id]/reset-password | 비밀번호 초기화 (관리자) | --- ## 4. 화면 설계 ### 4.1 로그인 페이지 (/login) ``` ┌─────────────────────────────────────────────────────────────────┐ │ │ │ 📊 주간보고 시스템 │ │ │ │ ┌─────────────────────────────────────┐ │ │ │ [G] Google로 로그인 │ │ │ └─────────────────────────────────────┘ │ │ ┌─────────────────────────────────────┐ │ │ │ [S] Synology로 로그인 │ │ ← 5번 작업 후 │ └─────────────────────────────────────┘ │ │ │ │ ─────────────── 또는 ─────────────── │ │ │ │ 이메일: [_________________________] │ │ 비밀번호: [_________________________] │ │ │ │ [로그인] [비밀번호 찾기] │ │ │ └─────────────────────────────────────────────────────────────────┘ ``` ### 4.2 비밀번호 설정 페이지 (/auth/set-password) ``` ┌─────────────────────────────────────────────────────────────────┐ │ │ │ 🔐 비밀번호 설정 │ │ │ │ Google 계정으로 로그인되었습니다. │ │ 비상시 로그인을 위해 비밀번호를 설정해주세요. │ │ │ │ 새 비밀번호: [_________________________] │ │ 비밀번호 확인: [_________________________] │ │ │ │ ※ 8자 이상, 영문+숫자 조합 권장 │ │ │ │ [비밀번호 설정] │ │ │ │ [나중에 설정하기 →] │ │ │ └─────────────────────────────────────────────────────────────────┘ * "나중에 설정하기" 클릭 시 메인으로 이동하지만, 다음 로그인 시 다시 안내 ``` ### 4.3 비밀번호 찾기 페이지 (/auth/find-password) ``` ┌─────────────────────────────────────────────────────────────────┐ │ │ │ 🔑 비밀번호 찾기 │ │ │ │ 등록된 정보와 일치하면 이메일로 임시 비밀번호를 발송합니다. │ │ │ │ 이름: [_________________________] │ │ 이메일: [_________________________] │ │ 핸드폰: [_________________________] │ │ │ │ [임시 비밀번호 발송] │ │ │ │ [← 로그인으로] │ │ │ └─────────────────────────────────────────────────────────────────┘ ↓ 발송 성공 시 ↓ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ ✅ 발송 완료 │ │ │ │ 임시 비밀번호가 이메일로 발송되었습니다. │ │ 이메일: hyo****@company.com │ │ │ │ ※ 로그인 후 비밀번호를 변경해주세요. │ │ │ │ [로그인하러 가기] │ │ │ └─────────────────────────────────────────────────────────────────┘ ``` ### 4.4 로그인 실패 시 (매칭 안됨) ``` ┌─────────────────────────────────────────────────────────────────┐ │ │ │ ⚠️ 로그인 실패 │ │ │ │ "unknown@gmail.com"은 등록되지 않은 사용자입니다. │ │ │ │ 시스템 사용을 위해서는 관리자에게 문의하여 │ │ 사용자 등록을 요청해주세요. │ │ │ │ 관리자 연락처: admin@company.com │ │ │ │ [다시 로그인] │ │ │ └─────────────────────────────────────────────────────────────────┘ ``` ### 4.4 마이페이지 - 비밀번호 변경 (/mypage) ``` ┌─────────────────────────────────────────────────────────────────┐ │ 마이페이지 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ 👤 기본 정보 │ │ ─────────────────────────────────────────────────────────────── │ │ 이름: 조효성 │ │ 이메일: hyosung@company.com │ │ 소속: 개발팀 │ │ 권한: 관리자 │ │ │ │ 🔗 Google 연결 │ │ ─────────────────────────────────────────────────────────────── │ │ 상태: ✅ 연결됨 (hyosung@gmail.com) │ │ 연결일: 2026-01-10 │ │ │ │ 🔒 비밀번호 변경 │ │ ─────────────────────────────────────────────────────────────── │ │ 현재 비밀번호: [_________________________] │ │ 새 비밀번호: [_________________________] │ │ 비밀번호 확인: [_________________________] │ │ │ │ [비밀번호 변경] │ │ │ │ 마지막 로그인: 2026-01-10 09:30 (Google) │ │ │ └─────────────────────────────────────────────────────────────────┘ ``` ### 4.5 관리자 - 사용자 관리 수정 (/admin/user) ``` ┌─────────────────────────────────────────────────────────────────┐ │ 사용자 상세 [수정] [삭제] │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ 기본 정보 │ │ ─────────────────────────────────────────────────────────────── │ │ 이름: 조효성 │ │ 이메일: hyosung@company.com │ │ ... │ │ │ │ 🔐 계정 관리 │ │ ─────────────────────────────────────────────────────────────── │ │ Google 연결: ✅ 연결됨 (hyosung@gmail.com) [연결 해제] │ │ 비밀번호: ******** [초기화] │ │ 마지막 로그인: 2026-01-10 09:30 │ │ │ └─────────────────────────────────────────────────────────────────┘ * [초기화] 클릭 → 임시 비밀번호 생성 → 사용자에게 전달 ``` --- ## 5. 환경 설정 ### 5.1 환경 변수 ```env # .env (공통) # Google OAuth GOOGLE_CLIENT_ID=xxx.apps.googleusercontent.com GOOGLE_CLIENT_SECRET=xxx GOOGLE_REDIRECT_URI=https://weeklyreport.company.com/api/auth/google/callback # 이메일 발송 (비밀번호 찾기용) SMTP_HOST=smtp.gmail.com SMTP_PORT=587 SMTP_USER=noreply@company.com SMTP_PASS=xxx SMTP_FROM=주간보고시스템 ``` ### 5.2 개발/운영 분기 (필요 시) ```env # .env.development GOOGLE_REDIRECT_URI=http://localhost:3000/api/auth/google/callback # .env.production GOOGLE_REDIRECT_URI=https://weeklyreport.company.com/api/auth/google/callback ``` --- ## 6. Google OAuth 설정 ### 6.1 Google Cloud Console 설정 1. **프로젝트 생성**: Google Cloud Console 2. **OAuth 동의 화면 설정**: - 앱 이름: 주간보고 시스템 - 범위: email, profile 3. **사용자 인증 정보 생성**: - OAuth 2.0 클라이언트 ID - 승인된 리디렉션 URI: `https://weeklyreport.company.com/api/auth/google/callback` ### 6.2 OAuth 흐름 ``` 1. 사용자 → [Google로 로그인] 클릭 2. 서버 → Google 인증 페이지로 리다이렉트 3. 사용자 → Google 계정 선택, 권한 승인 4. Google → 콜백 URL로 리다이렉트 (code 포함) 5. 서버 → code로 access_token 요청 6. 서버 → access_token으로 사용자 정보 요청 7. 서버 → email로 wr_employee_info 조회 - 있으면: 세션 생성, 로그인 완료 - 없으면: 에러 페이지 표시 ``` --- ## 7. 보안 고려사항 ### 7.1 비밀번호 정책 | 항목 | 정책 | |------|------| | 최소 길이 | 8자 이상 | | 복잡도 | 영문 + 숫자 조합 권장 | | 해시 알고리즘 | bcrypt (salt rounds: 10) | | 임시 비밀번호 | 랜덤 생성 (12자, 영문+숫자+특수문자) | ### 7.2 세션 관리 | 항목 | 설정 | |------|------| | 세션 유효기간 | 24시간 (또는 설정 가능) | | 세션 저장소 | 기존 방식 유지 (쿠키/메모리) | | 동시 로그인 | 허용 (기기별 세션) | ### 7.3 비밀번호 찾기 이메일 템플릿 ``` 제목: [주간보고시스템] 임시 비밀번호 안내 ─────────────────────────────────────── 안녕하세요, {이름}님. 요청하신 임시 비밀번호를 안내드립니다. 임시 비밀번호: {임시비밀번호} 보안을 위해 로그인 후 반드시 비밀번호를 변경해주세요. ※ 본 메일은 발신 전용입니다. ※ 본인이 요청하지 않은 경우 관리자에게 문의해주세요. ─────────────────────────────────────── 주간보고시스템 ``` --- ## 8. 작업 일정 ### Phase 1: DB + 환경 설정 (1일) - [ ] 시작: - [ ] 완료: - [ ] 소요시간: **작업 내용:** - [ ] wr_employee_info 컬럼 추가 (password_hash, google_id 등) - [ ] wr_login_history 테이블 생성 (선택) - [ ] 환경 변수 설정 (Google OAuth, SMTP) - [ ] Google Cloud Console OAuth 설정 --- ### Phase 2: 비밀번호 인증 (1.5일) - [ ] 시작: - [ ] 완료: - [ ] 소요시간: **작업 내용:** - [ ] bcrypt 해시 처리 - [ ] 이메일/비밀번호 로그인 API - [ ] 비밀번호 변경 API - [ ] 비밀번호 초기화 API (관리자) --- ### Phase 3: Google OAuth (1.5일) - [ ] 시작: - [ ] 완료: - [ ] 소요시간: **작업 내용:** - [ ] Google OAuth 시작/콜백 API - [ ] 사용자 매칭 로직 (email 기준) - [ ] 비밀번호 미설정 시 설정 페이지 리다이렉트 - [ ] 비밀번호 최초 설정 API --- ### Phase 4: 비밀번호 찾기 + 이메일 발송 (1일) - [ ] 시작: - [ ] 완료: - [ ] 소요시간: **작업 내용:** - [ ] 이메일 발송 유틸 (nodemailer) - [ ] 비밀번호 찾기 API (이름+이메일+핸드폰 매칭) - [ ] 임시 비밀번호 생성 및 발송 - [ ] 비밀번호 찾기 페이지 --- ### Phase 5: 로그인 UI + 테스트 (1일) - [ ] 시작: - [ ] 완료: - [ ] 소요시간: **작업 내용:** - [ ] 로그인 페이지 (OAuth + 비밀번호) - [ ] 비밀번호 설정 페이지 - [ ] 로그인 실패 페이지 - [ ] 마이페이지 비밀번호 변경 UI - [ ] 관리자 사용자 관리 수정 (비밀번호 초기화) - [ ] 전체 플로우 테스트 --- ## 작업 완료 결과 ### Phase별 작업 시간 | Phase | 작업 내용 | 시작 | 완료 | 소요시간 | |:-----:|----------|:----:|:----:|:--------:| | 1 | DB + 환경 설정 | - | - | - | | 2 | 비밀번호 인증 | - | - | - | | 3 | Google OAuth | - | - | - | | 4 | 비밀번호 찾기 + 이메일 발송 | - | - | - | | 5 | 로그인 UI + 테스트 | - | - | - | | | | | **총 소요시간** | **-** | --- ### 생성/수정된 파일 | 구분 | 파일 | 작업 | |------|------|:----:| | **DB** | wr_employee_info | 수정 (컬럼 추가) | | **DB** | wr_login_history | 신규 테이블 (선택) | | **API** | backend/api/auth/google.get.ts | 신규 | | **API** | backend/api/auth/google/callback.get.ts | 신규 | | **API** | backend/api/auth/login.post.ts | 수정 | | **API** | backend/api/auth/set-password.post.ts | 신규 | | **API** | backend/api/auth/change-password.put.ts | 신규 | | **API** | backend/api/auth/find-password.post.ts | 신규 | | **API** | backend/api/admin/user/[id]/reset-password.put.ts | 신규 | | **Frontend** | frontend/pages/login.vue | 수정 | | **Frontend** | frontend/pages/auth/set-password.vue | 신규 | | **Frontend** | frontend/pages/auth/find-password.vue | 신규 | | **Frontend** | frontend/pages/mypage.vue | 수정 | | **Frontend** | frontend/pages/admin/user/[id].vue | 수정 | | **Utils** | backend/utils/password.ts | 신규 | | **Utils** | backend/utils/email.ts | 신규 | | **Config** | .env | 수정 (OAuth, SMTP 설정) | --- ## 9. 기술 스택 - **Backend**: Nitro (H3) + PostgreSQL - **Frontend**: Nuxt3 + Vue3 + Bootstrap 5 - **OAuth**: Google OAuth 2.0 - **비밀번호**: bcrypt - **이메일 발송**: nodemailer - **세션**: 기존 방식 유지 --- ## 10. 향후 확장 고려 1. **Synology SSO 연동**: 다음 작업 (5번) 2. **2단계 인증 (2FA)**: TOTP 기반 추가 인증 3. **소셜 로그인 확장**: Microsoft, Kakao 등 4. **비밀번호 만료**: 90일 주기 변경 강제 5. **로그인 알림**: 새 기기 로그인 시 이메일 알림 6. **임시 비밀번호 만료**: 24시간 후 만료 처리