# 이메일 코드 인증 가이드 ## 📧 개요 링크 클릭 방식 대신 **6자리 숫자 코드 입력 방식**의 이메일 인증을 사용합니다. 이는 스팸/피싱 의심을 줄이고 더 안전한 인증 경험을 제공합니다. ## ✨ 주요 기능 ### 1. 회원가입 이메일 인증 - 회원가입 시 입력한 이메일로 6자리 인증 코드 발송 - 코드 입력 및 검증 후 회원가입 완료 - 코드 유효 시간: 5분 - 최대 5회 시도 가능 ### 2. 비밀번호 재설정 이메일 인증 - 비밀번호 찾기 시 이메일로 6자리 인증 코드 발송 - 코드 검증 후 비밀번호 재설정 페이지로 이동 - 코드 유효 시간: 5분 - 재설정 페이지 접근 유효 시간: 10분 ### 3. 코드 재전송 - 코드가 만료되거나 받지 못한 경우 재전송 가능 - 재전송은 첫 발송 후 30초 경과 시 가능 ## 🎨 UI/UX 특징 ### 1. 6자리 코드 입력 - 각 자리별 개별 입력 필드 - 자동으로 다음 칸으로 포커스 이동 - 붙여넣기 지원 (6자리 숫자 자동 분배) - 백스페이스로 이전 칸으로 이동 ### 2. 실시간 타이머 - 남은 시간을 시각적으로 표시 (분:초) - 시간 만료 시 경고 메시지 - 재전송 버튼 활성화 타이밍 표시 ### 3. 에러 처리 - 잘못된 코드 입력 시 shake 애니메이션 - 남은 시도 횟수 표시 - 명확한 에러 메시지 ## 🏗️ 아키텍처 ### Frontend Component: `EmailCodeVerification.vue` #### Props ```typescript interface Props { email: string // 인증 대상 이메일 title?: string // 제목 (기본값: '이메일 인증') expirySeconds?: number // 만료 시간 (기본값: 300초 = 5분) } ``` #### Events ```typescript // 코드 검증 요청 emit('verify', code: string) // 코드 재전송 요청 emit('resend') ``` #### 사용 예시 ```vue ``` ### Backend API #### 1. 코드 발송 ``` POST /api/email/send-code Content-Type: application/json { "email": "user@humetro.busan.kr", "type": "signup" // 또는 "password_reset" } ``` **Response:** ```json { "success": true, "message": "인증 코드를 이메일로 전송했습니다.", "debug_code": "123456" // 개발 환경에서만 } ``` #### 2. 코드 검증 ``` POST /api/email/verify-code Content-Type: application/json { "email": "user@humetro.busan.kr", "code": "123456", "type": "signup" // 또는 "password_reset" } ``` **Response (성공):** ```json { "success": true, "message": "인증이 완료되었습니다." } ``` **Response (실패):** ```json { "success": false, "error": "인증 코드가 올바르지 않습니다. (남은 시도: 3회)" } ``` ## 🔐 보안 기능 ### 1. 코드 생성 - 6자리 무작위 숫자 생성 (`random.choices(string.digits, k=6)`) - 각 이메일/타입별 고유 세션 키 사용 - 코드는 세션에 암호화되어 저장 ### 2. 검증 제한 - **시도 횟수 제한**: 5회까지만 시도 가능 - **시간 제한**: 5분 후 자동 만료 - **일회성**: 한 번 검증되면 코드 즉시 삭제 ### 3. 도메인 제한 - `@humetro.busan.kr` 도메인만 허용 - 백엔드에서 이메일 도메인 검증 ### 4. 세션 관리 ```python # 코드 저장 (5분간 유효) session[f"email_code_{email}_{type}"] = { "code": "123456", "expiry": timestamp + 300, "attempts": 0 } # 검증 완료 표시 (10분간 유효) session[f"email_verified_{email}_{type}"] = { "verified_at": timestamp } ``` ## 📱 사용 흐름 ### 회원가입 흐름 ```mermaid sequenceDiagram participant U as User participant F as Frontend participant B as Backend participant E as Email U->>F: 회원가입 정보 입력 F->>B: POST /api/email/send-code B->>B: 6자리 코드 생성 B->>E: 이메일 발송 (TODO) B->>F: {success: true} F->>U: 코드 입력 화면 표시 U->>F: 코드 입력 F->>B: POST /api/email/verify-code B->>B: 코드 검증 B->>F: {success: true} F->>B: POST /auth/signup B->>F: 회원가입 완료 F->>U: 로그인 페이지로 이동 ``` ### 비밀번호 재설정 흐름 ```mermaid sequenceDiagram participant U as User participant F as Frontend participant B as Backend U->>F: 이메일 입력 F->>B: POST /api/email/send-code (type: password_reset) B->>F: {success: true} F->>U: 코드 입력 화면 U->>F: 코드 입력 F->>B: POST /api/email/verify-code B->>B: 세션에 인증 완료 표시 B->>F: {success: true} F->>F: /reset-password?email=...&verified=true U->>F: 새 비밀번호 입력 F->>B: POST /api/auth/reset-password B->>B: 세션에서 인증 확인 B->>B: 비밀번호 업데이트 B->>F: {success: true} F->>U: 로그인 페이지로 이동 ``` ## 🎯 회원가입 통합 ### SignupView.vue ```vue ``` ## 🔄 비밀번호 재설정 통합 ### ForgotPasswordView.vue → ResetPasswordView.vue ```vue ``` ```vue ``` ## 🔧 개발 환경 설정 ### 1. 이메일 발송 (TODO) 현재는 콘솔에만 코드를 출력하고, 개발 환경에서는 API 응답에 코드를 포함시킵니다: ```python # 개발 환경에서만 return { "success": True, "message": "인증 코드를 이메일로 전송했습니다.", "debug_code": code if app.debug else None } ``` 프로덕션에서는 실제 이메일 발송 서비스 연동 필요: - SMTP 서버 - SendGrid / AWS SES - Supabase Email (Docker 환경에서는 제한적) ### 2. 콘솔에서 코드 확인 백엔드 콘솔: ``` === 이메일 인증 코드 === To: user@humetro.busan.kr Code: 123456 Type: signup Expiry: 2025-10-14 15:30:00 ======================= ``` 프론트엔드 콘솔: ``` === 개발 환경 인증 코드 === 코드: 123456 ======================= ``` ## 📊 에러 처리 ### Frontend 에러 메시지 | 상황 | 메시지 | |------|--------| | 잘못된 코드 | "인증 코드가 올바르지 않습니다. (남은 시도: N회)" | | 시도 횟수 초과 | "인증 시도 횟수를 초과했습니다. 코드를 재전송해주세요." | | 코드 만료 | "인증 코드가 만료되었습니다. 코드를 재전송해주세요." | | 코드 미존재 | "인증 코드가 존재하지 않거나 만료되었습니다." | ### Backend 에러 응답 ```python # 시도 횟수 초과 if stored_data["attempts"] >= 5: session.pop(session_key, None) return { "success": False, "error": "인증 시도 횟수를 초과했습니다. 코드를 재전송해주세요." }, 400 # 만료 if datetime.now().timestamp() > stored_data["expiry"]: session.pop(session_key, None) return { "success": False, "error": "인증 코드가 만료되었습니다. 코드를 재전송해주세요." }, 400 # 불일치 if stored_data["code"] != code: stored_data["attempts"] += 1 session[session_key] = stored_data return { "success": False, "error": f"인증 코드가 올바르지 않습니다. (남은 시도: {5 - stored_data['attempts']}회)" }, 400 ``` ## 🎨 UI 커스터마이징 ### 다크모드 지원 ```css :root.dark .code-digit { background: #1a202c; border-color: #4a5568; color: #f7fafc; } :root.dark .timer { color: #a78bfa; } ``` ### 애니메이션 ```css /* Shake 애니메이션 (에러 시) */ @keyframes shake { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-5px); } 75% { transform: translateX(5px); } } .code-digit.error { border-color: #dc2626; animation: shake 0.3s; } ``` ## 📝 TODO (향후 개선사항) ### 1. 이메일 발송 구현 ```python # SMTP 또는 이메일 서비스 연동 import smtplib from email.mime.text import MIMEText def send_verification_email(email, code): msg = MIMEText(f"인증 코드: {code}") msg['Subject'] = '부산교통공사 1호선 - 이메일 인증' msg['From'] = 'noreply@humetro.busan.kr' msg['To'] = email # SMTP 발송... ``` ### 2. 이메일 템플릿 - HTML 이메일 템플릿 디자인 - 회사 로고 및 브랜딩 추가 - 다국어 지원 ### 3. 보안 강화 - Rate limiting (IP별 요청 제한) - Captcha 추가 (무차별 대입 공격 방지) - 로그 기록 (audit_logs) ### 4. 사용자 경험 개선 - 이메일 자동 완성 - 코드 자동 감지 (SMS/Email OTP) - 음성 안내 (접근성) ## 🔗 참고 자료 - [OWASP Authentication Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html) - [Email OTP Best Practices](https://www.twilio.com/docs/verify/email) - [Flask Session Management](https://flask.palletsprojects.com/en/2.3.x/quickstart/#sessions)