- Google OAuth 권한 과다 요청 문제점 추가 - 단계별 권한 요청 전략 제안 (기본 로그인 vs 스킬별 권한) - 구현 방안 및 Phase 4 로드맵 추가
253 lines
7.0 KiB
Markdown
253 lines
7.0 KiB
Markdown
# 로빙 프로젝트 인증 시스템 전체 분석 및 통합 방안
|
|
|
|
## 현재 구조 분석
|
|
|
|
### 1. 데이터베이스 (PostgreSQL - auth_db)
|
|
|
|
#### Users 테이블 구조
|
|
```sql
|
|
- id: UUID (Primary Key)
|
|
- username: VARCHAR(50) UNIQUE # happybell80 등
|
|
- email: VARCHAR(255) UNIQUE NOT NULL
|
|
- name: VARCHAR(255)
|
|
- picture: VARCHAR(500) # OAuth profile picture URL
|
|
- oauth_provider: VARCHAR(50) # google, github 등
|
|
- oauth_id: VARCHAR(255) # Provider의 user ID
|
|
- is_active: BOOLEAN
|
|
- created_at, updated_at, last_login_at: TIMESTAMP
|
|
```
|
|
|
|
#### WorkspaceMembers 테이블
|
|
```sql
|
|
- user_id: UUID (FK to users.id)
|
|
- workspace_id: UUID
|
|
- robing_id: VARCHAR(100) # rb8001, rb10508 등
|
|
- role: ENUM (owner, member, guest)
|
|
```
|
|
|
|
### 2. Auth Server (51123 서버, 포트 9000)
|
|
|
|
#### JWT 토큰 구조
|
|
```python
|
|
# 토큰 생성 시 페이로드 (gmail.py:183-188)
|
|
{
|
|
"sub": username, # "happybell80" - 주요 식별자
|
|
"email": user_email, # "goeun2dc@gmail.com"
|
|
"name": user_name, # "김고은"
|
|
"username": username, # "happybell80" (중복)
|
|
"exp": expires_at
|
|
}
|
|
```
|
|
|
|
#### 환경 변수
|
|
- JWT_SECRET_KEY: `ro-being-auth-jwt-secret-key-2024`
|
|
- JWT_ALGORITHM: `HS256`
|
|
- JWT_ACCESS_TOKEN_EXPIRE_MINUTES: 30일
|
|
|
|
#### 이메일-유저명 매핑 (하드코딩)
|
|
```python
|
|
# gmail.py:150-154
|
|
email_to_username = {
|
|
'goeun2dc@gmail.com': 'happybell80',
|
|
'eagle0914@gmail.com': 'eagle0914',
|
|
}
|
|
```
|
|
|
|
### 3. Frontend (frontend-customer)
|
|
|
|
#### 토큰 저장/조회
|
|
- **저장 키**: `auth_token` (auth-context.tsx:61)
|
|
- **조회**: `localStorage.getItem('auth_token')` (auth-context.tsx:29)
|
|
- **서버 URL**: `https://auth.ro-being.com` (하드코딩)
|
|
|
|
#### 현재 문제점
|
|
```typescript
|
|
// robing-api.ts - 토큰 전송 안함!
|
|
export async function sendMessage(text: string, userId: string = 'test_user') {
|
|
// Authorization 헤더 없음
|
|
// 모든 사용자가 'test_user'로 처리됨
|
|
}
|
|
```
|
|
|
|
### 4. Robing Gateway (포트 10100)
|
|
|
|
#### 현재 처리 방식
|
|
```python
|
|
# main.py:92-95
|
|
x_user_id: Optional[str] = Header(None) # X-User-Id 헤더만 확인
|
|
# JWT 토큰 검증 없음!
|
|
```
|
|
|
|
### 5. Robing Services (51124 서버)
|
|
|
|
#### ChromaDB 컬렉션명 생성
|
|
```python
|
|
# storage.py:84 (추정)
|
|
collection_name = f"{robing_id}_{user_id}_episodic"
|
|
# 현재: rb10508_test_default_episodic (모든 사용자 공유!)
|
|
```
|
|
|
|
## 주요 문제점
|
|
|
|
### 1. 인증 토큰 미전송 ⚠️
|
|
- Frontend가 API 호출 시 JWT 토큰을 전송하지 않음
|
|
- `robing-api.ts`에 Authorization 헤더 없음
|
|
- 모든 사용자가 'test_user'로 처리
|
|
|
|
### 2. 백엔드 토큰 미검증 ⚠️
|
|
- Robing Gateway가 JWT 토큰을 검증하지 않음
|
|
- X-User-Id 헤더만 확인 (누구나 위조 가능)
|
|
|
|
### 3. 사용자 식별 실패 ⚠️
|
|
- username이 제대로 전달되지 않아 'default'로 폴백
|
|
- ChromaDB 컬렉션을 모든 사용자가 공유
|
|
|
|
### 4. 이메일-유저명 매핑 하드코딩 📝
|
|
- 새 사용자 추가 시 코드 수정 필요
|
|
- 확장성 없음
|
|
|
|
### 5. OAuth 권한 과다 요청 🔐
|
|
- 회원가입/로그인 시 Gmail 읽기/쓰기 권한(`gmail.modify`)까지 요청
|
|
- 복잡한 동의 과정으로 사용자 이탈 가능성 높음
|
|
- 이메일 기능 미사용자에게도 과도한 권한 요청
|
|
|
|
### 6. 변수명 불일치 혼란 🔄
|
|
- user_id vs username vs email 혼용
|
|
- JWT의 'sub'가 username인지 user_id인지 불명확
|
|
|
|
## 결정 필요 사항
|
|
|
|
### 1. 주요 식별자 선택
|
|
- [ ] **username** (추천): 'happybell80' - 인간 친화적, URL 안전
|
|
- [ ] **user_id (UUID)**: 'a1b2c3d4-...' - DB 표준, 중복 없음
|
|
- [ ] **email**: 'goeun2dc@gmail.com' - OAuth 표준, 변경 가능성
|
|
|
|
### 2. JWT 페이로드 표준화
|
|
```json
|
|
옵션 A (username 중심):
|
|
{
|
|
"sub": "happybell80", // 주 식별자
|
|
"user_id": "uuid-here", // DB ID
|
|
"email": "goeun2dc@gmail.com",
|
|
"name": "김고은"
|
|
}
|
|
|
|
옵션 B (UUID 중심):
|
|
{
|
|
"sub": "uuid-here", // 주 식별자
|
|
"username": "happybell80",
|
|
"email": "goeun2dc@gmail.com",
|
|
"name": "김고은"
|
|
}
|
|
```
|
|
|
|
### 3. API 헤더 표준화
|
|
```
|
|
옵션 A (Bearer 토큰만):
|
|
Authorization: Bearer <jwt_token>
|
|
|
|
옵션 B (Bearer + X-User-Id):
|
|
Authorization: Bearer <jwt_token>
|
|
X-User-Id: happybell80 // 빠른 조회용
|
|
|
|
옵션 C (Bearer + X-Username):
|
|
Authorization: Bearer <jwt_token>
|
|
X-Username: happybell80 // 명확한 이름
|
|
```
|
|
|
|
### 4. ChromaDB 컬렉션 네이밍
|
|
```
|
|
옵션 A: {robing_id}_{username}_episodic
|
|
예: rb10508_happybell80_episodic
|
|
|
|
옵션 B: {robing_id}_{user_uuid}_episodic
|
|
예: rb10508_a1b2c3d4_episodic
|
|
|
|
옵션 C: {workspace_id}_{robing_id}_{username}_episodic
|
|
예: workspace1_rb10508_happybell80_episodic
|
|
```
|
|
|
|
### 5. 토큰 저장 키 통일
|
|
```javascript
|
|
현재: 'auth_token'
|
|
대안: 'jwt_token', 'access_token', 'robing_token'
|
|
```
|
|
|
|
### 6. OAuth 권한 분리 전략
|
|
```python
|
|
# 옵션 A: 단계별 권한 요청 (추천) ✅
|
|
기본 로그인: openid, userinfo.email, userinfo.profile
|
|
이메일 스킬: gmail.modify (별도 연결)
|
|
캘린더 스킬: calendar.events (별도 연결)
|
|
|
|
# 옵션 B: 일괄 권한 요청 (현재)
|
|
모든 권한을 한 번에 요청 (사용자 이탈 높음)
|
|
```
|
|
|
|
**구현 방안:**
|
|
- `/auth/gmail/login` - 기본 프로필 권한만 (간단한 로그인)
|
|
- `/auth/gmail/connect-email` - Gmail 권한 추가 (이메일 아이템 사용 시)
|
|
- DB에 권한 레벨 저장: `oauth_scopes` 필드 추가
|
|
- Frontend에서 권한 상태 표시 및 추가 연결 버튼 제공
|
|
|
|
## 즉시 수정 필요 (Critical)
|
|
|
|
### 1. Frontend (robing-api.ts)
|
|
```typescript
|
|
// 토큰 전송 추가
|
|
const token = localStorage.getItem('auth_token');
|
|
headers['Authorization'] = `Bearer ${token}`;
|
|
```
|
|
|
|
### 2. Gateway (main.py)
|
|
```python
|
|
# JWT 검증 추가
|
|
from app.core.auth import decode_access_token
|
|
|
|
authorization = Header(None)
|
|
if authorization:
|
|
token = authorization.replace("Bearer ", "")
|
|
payload = decode_access_token(token)
|
|
username = payload.get("sub") # 또는 username
|
|
```
|
|
|
|
### 3. Robing Service (storage.py)
|
|
```python
|
|
# username 기반 컬렉션 생성
|
|
collection_name = f"{robing_id}_{username}_episodic"
|
|
```
|
|
|
|
## 단계별 구현 계획
|
|
|
|
### Phase 1: 긴급 패치 (1일)
|
|
1. Frontend에서 토큰 전송
|
|
2. Gateway에서 토큰 검증
|
|
3. username 기반 ChromaDB 분리
|
|
|
|
### Phase 2: 표준화 (3일)
|
|
1. 변수명 통일 (username vs user_id)
|
|
2. JWT 페이로드 표준화
|
|
3. API 문서 작성
|
|
|
|
### Phase 3: 개선 (1주)
|
|
1. 이메일-유저명 매핑 DB화
|
|
2. 토큰 갱신 로직 구현
|
|
3. 권한 체계 구현
|
|
|
|
### Phase 4: OAuth 권한 분리 (1주)
|
|
1. 기본 로그인용 엔드포인트 구현 (최소 권한)
|
|
2. 스킬별 추가 권한 연결 엔드포인트 구현
|
|
3. DB에 사용자별 권한 상태 저장
|
|
4. Frontend에 권한 관리 UI 추가
|
|
|
|
## 참고 사항
|
|
|
|
- **JWT Secret**: 모든 서비스가 같은 키 공유 필요
|
|
- **CORS 설정**: frontend URL 추가 필요
|
|
- **Redis**: 토큰 캐싱 및 세션 관리 활용
|
|
- **로그**: 모든 인증 실패 상세 로깅
|
|
|
|
## 문서 작성자
|
|
- 작성일: 2025-08-16
|
|
- 작성자: 51123 서버 관리 Claude
|
|
- 목적: 인증 시스템 통합을 위한 현황 분석 |