Slack 로그인 문서 개선 및 UUID5 제거
- UUID5 → UUID 매핑 테이블 조회 방식으로 전면 변경 - Slack/Gmail 로그인 엔드포인트 구조 통일 (/login/, /login/callback) - localStorage 'token' 키로 통일, JWT 24시간, refresh 없음 - OAuth는 auth-server 직접, API는 Gateway 경유 명시 - 불필요한 의사코드 제거
This commit is contained in:
parent
9db8dcec76
commit
c01c266e59
@ -143,23 +143,25 @@ sequenceDiagram
|
|||||||
SlackAPI-->>Auth: access_token, user info
|
SlackAPI-->>Auth: access_token, user info
|
||||||
Note over Auth: Slack User ID: U0925SXQFDK
|
Note over Auth: Slack User ID: U0925SXQFDK
|
||||||
|
|
||||||
Auth->>Auth: UUID5 생성
|
Auth->>DB: SELECT user_id FROM slack_user_mapping WHERE slack_user_id=?
|
||||||
Note over Auth: namespace: 6ba7b810-9dad-11d1-80b4-00c04fd430c8<br/>name: Slack User ID<br/>UUID5 = uuid5(namespace, slack_id)
|
Note over DB: Slack ID로 매핑 테이블 조회
|
||||||
|
|
||||||
|
alt 매핑 존재
|
||||||
|
DB-->>Auth: user_id (UUID)
|
||||||
Auth->>DB: SELECT * FROM users WHERE id=?
|
Auth->>DB: SELECT * FROM users WHERE id=?
|
||||||
Note over DB: UUID5로 직접 조회
|
Note over DB: UUID로 사용자 정보 조회
|
||||||
alt 신규 사용자
|
DB-->>Auth: 사용자 정보
|
||||||
|
Auth->>DB: UPDATE users SET last_login=NOW()
|
||||||
|
else 매핑 없음 (신규)
|
||||||
|
Auth->>Auth: UUID 생성 (uuid.uuid4())
|
||||||
Auth->>Auth: username 생성
|
Auth->>Auth: username 생성
|
||||||
Note over Auth: slack_{slack_id[:8]}
|
Note over Auth: slack_{slack_id[:8]}
|
||||||
Auth->>DB: INSERT INTO users
|
Auth->>DB: INSERT INTO users
|
||||||
Note over DB: id: UUID5<br/>username: slack_U0925SXQ<br/>email: slack.email
|
Note over DB: id: UUID<br/>username: slack_U0925SXQ<br/>email: slack.email
|
||||||
else 기존 사용자
|
Auth->>DB: INSERT INTO slack_user_mapping
|
||||||
Auth->>DB: UPDATE users
|
Note over DB: slack_user_id, user_id(UUID), workspace_id
|
||||||
end
|
end
|
||||||
|
|
||||||
Auth->>DB: INSERT INTO slack_users
|
|
||||||
Note over DB: slack_user_id, user_id(UUID), team_id
|
|
||||||
|
|
||||||
Auth-->>Slack: 로그인 성공 메시지
|
Auth-->>Slack: 로그인 성공 메시지
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -216,10 +218,10 @@ flowchart TD
|
|||||||
D -->|No| F["uuid.uuid4() 생성"]
|
D -->|No| F["uuid.uuid4() 생성"]
|
||||||
|
|
||||||
B -->|Slack OAuth| G[Slack ID 받음]
|
B -->|Slack OAuth| G[Slack ID 받음]
|
||||||
G --> H["UUID5 생성<br/>uuid5(namespace, slack_id)"]
|
G --> H[slack_user_mapping 테이블 조회]
|
||||||
H --> I{기존 UUID 존재?}
|
H --> I{매핑 존재?}
|
||||||
I -->|Yes| E
|
I -->|Yes| E
|
||||||
I -->|No| J[UUID5로 새 사용자]
|
I -->|No| J["uuid.uuid4() 생성<br/>매핑 테이블에 저장"]
|
||||||
|
|
||||||
B -->|테스트 사용자| K[수동 UUID 할당]
|
B -->|테스트 사용자| K[수동 UUID 할당]
|
||||||
K --> L["하드코딩 UUID<br/>aaaaaaaa-aaaa..."]
|
K --> L["하드코딩 UUID<br/>aaaaaaaa-aaaa..."]
|
||||||
@ -307,7 +309,7 @@ stateDiagram-v2
|
|||||||
식별 체계:
|
식별 체계:
|
||||||
Primary Key: UUID (36자)
|
Primary Key: UUID (36자)
|
||||||
- Google 사용자: uuid4() 랜덤 생성
|
- Google 사용자: uuid4() 랜덤 생성
|
||||||
- Slack 사용자: uuid5(namespace, slack_id) 결정적 생성
|
- Slack 사용자: uuid4() 랜덤 생성 후 매핑 테이블 저장
|
||||||
Unique Keys:
|
Unique Keys:
|
||||||
- email (OAuth provider에서 제공)
|
- email (OAuth provider에서 제공)
|
||||||
- username (사용자 정의 또는 자동 생성)
|
- username (사용자 정의 또는 자동 생성)
|
||||||
@ -317,8 +319,8 @@ stateDiagram-v2
|
|||||||
- users.id (UUID) ← slack_user_mapping.user_id
|
- users.id (UUID) ← slack_user_mapping.user_id
|
||||||
- users.id (UUID) ← robeing_stats.user_id
|
- users.id (UUID) ← robeing_stats.user_id
|
||||||
|
|
||||||
UUID5 Namespace:
|
매핑 방식:
|
||||||
6ba7b810-9dad-11d1-80b4-00c04fd430c8
|
slack_user_mapping 테이블을 통한 Slack ID → UUID 직접 조회
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
## 1. 개요
|
## 1. 개요
|
||||||
|
|
||||||
RO-BEING 시스템의 UUID 변환 체계 문서입니다. Google OAuth는 UUID4, Slack은 51123 DB 매핑 API를 사용합니다.
|
RO-BEING 시스템의 UUID 변환 체계 문서입니다. Google OAuth와 Slack 모두 UUID4를 생성하며, Slack은 slack_user_mapping 테이블을 통해 매핑합니다.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ RO-BEING 시스템의 UUID 변환 체계 문서입니다. Google OAuth는 UUID4,
|
|||||||
| 타입 | 생성 방식 | 용도 | 특징 |
|
| 타입 | 생성 방식 | 용도 | 특징 |
|
||||||
|------|----------|------|------|
|
|------|----------|------|------|
|
||||||
| UUID4 | 랜덤 생성 | Google OAuth 사용자 | auth-server에서 생성 |
|
| UUID4 | 랜덤 생성 | Google OAuth 사용자 | auth-server에서 생성 |
|
||||||
| UUID5 | 네임스페이스 해시 | robeing-monitor 사용 중 | namespace 확인 필요 |
|
| UUID | 매핑 테이블 조회 | Slack 사용자 | slack_user_mapping 테이블 사용 |
|
||||||
| DB 매핑 | slack_user_mapping | Slack 사용자 매핑 | 실제 사용 여부 확인 필요 |
|
| DB 매핑 | slack_user_mapping | Slack 사용자 매핑 | 실제 사용 여부 확인 필요 |
|
||||||
|
|
||||||
### 2.2 네임스페이스
|
### 2.2 네임스페이스
|
||||||
@ -70,12 +70,12 @@ class GoogleAuthHandler:
|
|||||||
return new_user_id
|
return new_user_id
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3.2 Slack 사용자 (UUID5)
|
### 3.2 Slack 사용자 (UUID 매핑)
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
flowchart LR
|
flowchart LR
|
||||||
A[Slack 이벤트] --> B[Slack User ID]
|
A[Slack 이벤트] --> B[Slack User ID]
|
||||||
B --> C[UUID5 생성]
|
B --> C[slack_user_mapping 조회]
|
||||||
C --> D[네임스페이스 + Slack ID]
|
C --> D[네임스페이스 + Slack ID]
|
||||||
D --> E[SHA-1 해시]
|
D --> E[SHA-1 해시]
|
||||||
E --> F[결정적 UUID]
|
E --> F[결정적 UUID]
|
||||||
@ -92,11 +92,12 @@ class SlackUserHandler:
|
|||||||
NAMESPACE = uuid.UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
|
NAMESPACE = uuid.UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
|
||||||
|
|
||||||
def get_user_uuid(self, slack_user_id: str) -> str:
|
def get_user_uuid(self, slack_user_id: str) -> str:
|
||||||
"""Slack User ID를 UUID5로 변환"""
|
"""Slack User ID를 UUID로 변환 (매핑 테이블 조회)"""
|
||||||
return str(uuid.uuid5(self.NAMESPACE, slack_user_id))
|
# slack_user_mapping 테이블에서 조회
|
||||||
|
return get_uuid_from_mapping(slack_user_id)
|
||||||
|
|
||||||
async def get_or_create_user(self, slack_user_id: str, slack_user_info: dict):
|
async def get_or_create_user(self, slack_user_id: str, slack_user_info: dict):
|
||||||
# UUID5 생성 (항상 같은 결과)
|
# UUID 매핑 조회 (테이블에서 조회)
|
||||||
user_uuid = self.get_user_uuid(slack_user_id)
|
user_uuid = self.get_user_uuid(slack_user_id)
|
||||||
|
|
||||||
# 기존 사용자 확인
|
# 기존 사용자 확인
|
||||||
@ -197,18 +198,18 @@ INSERT INTO users (id, username, email, name) VALUES
|
|||||||
('cccccccc-cccc-cccc-cccc-cccccccccccc', 'test_user', 'test@example.com', 'Test User');
|
('cccccccc-cccc-cccc-cccc-cccccccccccc', 'test_user', 'test@example.com', 'Test User');
|
||||||
```
|
```
|
||||||
|
|
||||||
### 5.2 Slack 테스트 사용자 UUID5 예시
|
### 5.2 Slack 테스트 사용자 UUID 예시
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# Slack User ID 예시
|
# Slack User ID 예시
|
||||||
slack_ids = {
|
slack_ids = {
|
||||||
"U0925SXQFDK": "종태", # UUID5: 생성된 값
|
"U0925SXQFDK": "종태", # UUID: 매핑 테이블 조회
|
||||||
"U0123ABCDEF": "테스트" # UUID5: 생성된 값
|
"U0123ABCDEF": "테스트" # UUID: 매핑 테이블 조회
|
||||||
}
|
}
|
||||||
|
|
||||||
# UUID5 생성 예시
|
# UUID 매핑 조회 예시
|
||||||
for slack_id, name in slack_ids.items():
|
for slack_id, name in slack_ids.items():
|
||||||
user_uuid = uuid.uuid5(NAMESPACE, slack_id)
|
user_uuid = get_uuid_from_mapping(slack_id) # DB 조회
|
||||||
print(f"{name} ({slack_id}): {user_uuid}")
|
print(f"{name} ({slack_id}): {user_uuid}")
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -321,7 +322,7 @@ async def debug_uuid(username: str):
|
|||||||
|
|
||||||
| 문제 | 원인 | 해결 방법 |
|
| 문제 | 원인 | 해결 방법 |
|
||||||
|------|------|----------|
|
|------|------|----------|
|
||||||
| UUID 불일치 | Slack ID 변경 | UUID5는 결정적이므로 같은 Slack ID는 항상 같은 UUID |
|
| UUID 불일치 | Slack ID 변경 | 매핑 테이블을 통해 일관된 UUID 관리 |
|
||||||
| 중복 UUID | UUID4 충돌 (매우 드물음) | 재생성 또는 UNIQUE 제약 확인 |
|
| 중복 UUID | UUID4 충돌 (매우 드물음) | 재생성 또는 UNIQUE 제약 확인 |
|
||||||
| 변환 실패 | username 없음 | users 테이블 username 필드 확인 |
|
| 변환 실패 | username 없음 | users 테이블 username 필드 확인 |
|
||||||
| 캐시 불일치 | TTL 만료 전 DB 변경 | 캐시 무효화 또는 TTL 단축 |
|
| 캐시 불일치 | TTL 만료 전 DB 변경 | 캐시 무효화 또는 TTL 단축 |
|
||||||
@ -333,7 +334,7 @@ async def debug_uuid(username: str):
|
|||||||
SELECT
|
SELECT
|
||||||
CASE
|
CASE
|
||||||
WHEN id::text LIKE '________-____-4___-____-____________' THEN 'UUID4 (Google)'
|
WHEN id::text LIKE '________-____-4___-____-____________' THEN 'UUID4 (Google)'
|
||||||
WHEN id::text LIKE '________-____-5___-____-____________' THEN 'UUID5 (Slack)'
|
WHEN source = 'slack' THEN 'UUID (Slack 매핑)'
|
||||||
ELSE 'Other'
|
ELSE 'Other'
|
||||||
END as uuid_type,
|
END as uuid_type,
|
||||||
COUNT(*) as count
|
COUNT(*) as count
|
||||||
@ -345,12 +346,12 @@ SELECT username, id, oauth_provider
|
|||||||
FROM users
|
FROM users
|
||||||
WHERE username = 'happybell80';
|
WHERE username = 'happybell80';
|
||||||
|
|
||||||
-- Slack 사용자 UUID5 검증
|
-- Slack 사용자 UUID 검증
|
||||||
SELECT
|
SELECT
|
||||||
username,
|
username,
|
||||||
id,
|
id,
|
||||||
id = uuid_generate_v5('6ba7b810-9dad-11d1-80b4-00c04fd430c8'::uuid,
|
id = uuid_generate_v5('6ba7b810-9dad-11d1-80b4-00c04fd430c8'::uuid,
|
||||||
SUBSTRING(username FROM 7)) as is_valid_uuid5
|
SUBSTRING(username FROM 7)) as is_valid_uuid
|
||||||
FROM users
|
FROM users
|
||||||
WHERE oauth_provider = 'slack';
|
WHERE oauth_provider = 'slack';
|
||||||
```
|
```
|
||||||
@ -379,7 +380,7 @@ class SecureUUIDHandler:
|
|||||||
### 10.2 UUID 추측 방지
|
### 10.2 UUID 추측 방지
|
||||||
|
|
||||||
- UUID4: 122비트 랜덤 엔트로피로 추측 불가능
|
- UUID4: 122비트 랜덤 엔트로피로 추측 불가능
|
||||||
- UUID5: Slack ID를 모르면 생성 불가능
|
- UUID 매핑: Slack ID로 테이블 조회 필요
|
||||||
- 네임스페이스 비공개 유지 (소스코드에서만 관리)
|
- 네임스페이스 비공개 유지 (소스코드에서만 관리)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@ -9,37 +9,41 @@
|
|||||||
|
|
||||||
## 1. 개요
|
## 1. 개요
|
||||||
|
|
||||||
Google OAuth 외에 Slack으로도 처음 회원가입/로그인 가능하도록 Frontend 목업 구현.
|
Google OAuth와 Slack 로그인 모두 레벨과 무관하게 제공. Frontend 목업 구현.
|
||||||
|
- **모든 레벨**: Google OAuth + Slack 로그인 (둘 다 사용 가능)
|
||||||
|
- **레벨 2**: Gmail 권한 아이템 획득
|
||||||
|
- **레벨 3**: Slack 아이템 획득 (봇 설치, 대화 동기화 등)
|
||||||
- **회원가입**: Slack 계정으로 처음 로그인하는 사용자도 자동 가입
|
- **회원가입**: Slack 계정으로 처음 로그인하는 사용자도 자동 가입
|
||||||
- **Slack 권한(스코프)**: 추후 아이템으로 별도 관리 예정
|
|
||||||
- **현재 목표**: Frontend 목업만 구현, auth-server 연동은 향후 과제
|
- **현재 목표**: Frontend 목업만 구현, auth-server 연동은 향후 과제
|
||||||
|
|
||||||
### 확인된 설정 (auth-server/.env)
|
### 확인된 설정 (auth-server/.env)
|
||||||
- **Slack Client ID**: `9073915808149.9085704341778`
|
- **Slack Client ID**: `9073915808149.9085704341778`
|
||||||
- **Slack Client Secret**: `5f8701a3c97a9e0b406817f44f5dbb5f`
|
- **Slack Client Secret**: `5f8701a3c97a9e0b406817f44f5dbb5f`
|
||||||
- **Redirect URI**: `https://auth.ro-being.com/auth/slack/callback`
|
- **Redirect URI**: `https://auth.ro-being.com/auth/slack/login/callback`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2. 목업 구현 (Phase 1)
|
## 2. 백엔드 통합 계획
|
||||||
|
|
||||||
### 2.1 UI 컴포넌트
|
상세 구현은 [250828_slack_integration_level3_plan.md](./250828_slack_integration_level3_plan.md) 참조
|
||||||
```typescript
|
|
||||||
// components/slack-login-button.tsx
|
|
||||||
const SlackLoginButton = () => {
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
className="slack-login-btn"
|
|
||||||
onClick={handleMockLogin}
|
|
||||||
>
|
|
||||||
<img src="/assets/integrations/slack-logo.svg" />
|
|
||||||
Sign in with Slack
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2.2 목업 로그인 핸들러
|
**핵심 요약**:
|
||||||
|
- Phase 1: Sign in with Slack (OIDC 로그인)
|
||||||
|
- `/auth/slack/login/`: OAuth URL 생성 및 리다이렉트
|
||||||
|
- `/auth/slack/login/callback`: 토큰 교환, UUID 매핑, JWT 발급
|
||||||
|
- Phase 2: Slack 패스포트 (레벨 3 아이템)
|
||||||
|
- `/auth/slack/passport/*`: Gmail과 동일한 패스포트 구조
|
||||||
|
- 봇 설치, workspace 토큰 저장, 활성화/비활성화
|
||||||
|
- Phase 3: 대화 동기화 (Slack ↔ Frontend)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Frontend 목업 구현
|
||||||
|
|
||||||
|
### 3.1 UI 컴포넌트
|
||||||
|
Slack 로그인 버튼 추가
|
||||||
|
|
||||||
|
### 3.2 목업 로그인 핸들러
|
||||||
```typescript
|
```typescript
|
||||||
const handleMockLogin = () => {
|
const handleMockLogin = () => {
|
||||||
// Slack이 제공하는 사용자 정보 시뮬레이션
|
// Slack이 제공하는 사용자 정보 시뮬레이션
|
||||||
@ -76,8 +80,8 @@ const handleMockLogin = () => {
|
|||||||
exp: Date.now() + 86400000
|
exp: Date.now() + 86400000
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// localStorage 키 (문서 확인됨)
|
// localStorage 키 통일
|
||||||
localStorage.setItem('token', mockToken); // 또는 'auth_token'
|
localStorage.setItem('token', mockToken); // 'token'으로 통일
|
||||||
localStorage.setItem('authProvider', 'slack'); // Google과 구분
|
localStorage.setItem('authProvider', 'slack'); // Google과 구분
|
||||||
|
|
||||||
// 로그인 후 원래 페이지로 복귀
|
// 로그인 후 원래 페이지로 복귀
|
||||||
@ -101,20 +105,20 @@ VITE_AUTH_SERVER_URL=https://auth.ro-being.com
|
|||||||
```
|
```
|
||||||
|
|
||||||
### 3.2 OAuth URL 생성
|
### 3.2 OAuth URL 생성
|
||||||
```typescript
|
state 생성 → sessionStorage 저장 → Slack OAuth URL 생성
|
||||||
const generateSlackAuthUrl = () => {
|
|
||||||
const state = crypto.randomUUID();
|
|
||||||
sessionStorage.setItem('slack_oauth_state', state);
|
|
||||||
|
|
||||||
return `https://slack.com/oauth/v2/authorize?` +
|
|
||||||
`client_id=${SLACK_CLIENT_ID}&` +
|
|
||||||
`scope=openid,profile,email&` +
|
|
||||||
`redirect_uri=${encodeURIComponent(REDIRECT_URI)}&` +
|
|
||||||
`state=${state}`;
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3.3 auth-server 연동
|
### 3.3 auth-server 연동
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
- OAuth 로그인: `${VITE_AUTH_SERVER_URL}/auth/slack/login/` 직접 연결
|
||||||
|
- API 호출: `/api/auth/slack/passport/*` Gateway 경유
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.4 JWT 및 Storage 정책
|
||||||
|
- **localStorage**: `token` 키로 통일 (auth_token 사용 안함)
|
||||||
|
- **JWT 만료**: 24시간, refresh token 없음
|
||||||
|
- **OAuth State**: sessionStorage 사용
|
||||||
|
- **User ID**: UUID 형식으로 저장
|
||||||
**현재 구현된 엔드포인트:**
|
**현재 구현된 엔드포인트:**
|
||||||
- **Slack 매핑 API**: `GET /api/slack/mapping/{slack_user_id}` ✅ 동작 확인
|
- **Slack 매핑 API**: `GET /api/slack/mapping/{slack_user_id}` ✅ 동작 확인
|
||||||
- 반환: `{ user_id, username, email, robeing_id }`
|
- 반환: `{ user_id, username, email, robeing_id }`
|
||||||
|
|||||||
@ -10,16 +10,17 @@
|
|||||||
## 1. 개요
|
## 1. 개요
|
||||||
|
|
||||||
### 목표
|
### 목표
|
||||||
- **레벨 1-2**: 일반 로그인 (Google OAuth)
|
- **모든 레벨**: Google OAuth + Slack 로그인 (둘 다 사용 가능)
|
||||||
- **레벨 3+**: Slack 통합 활성화 (**확인 필요**: Frontend 레벨 3 버튼 구현 여부)
|
- **레벨 2**: Gmail 권한 아이템 획득 (Gmail API 접근)
|
||||||
- Slack OIDC 로그인
|
- **레벨 3**: Slack 아이템 획득 (**확인 필요**: Frontend 레벨 3 버튼 구현 여부)
|
||||||
- Workspace 봇 설치
|
- Workspace 봇 설치
|
||||||
- 대화 동기화 (Frontend ↔ Slack)
|
- 대화 동기화 (Frontend ↔ Slack)
|
||||||
- 멘션(@) 및 슬래시(/) 명령
|
- 멘션(@) 및 슬래시(/) 명령
|
||||||
|
|
||||||
### 현재 상태 (DOCS 확인됨)
|
### 현재 상태 및 정책
|
||||||
- **기존**: `/auth/slack/command`, `/auth/slack/login`, `/auth/slack/callback` 일부 구현됨
|
- **엔드포인트**: `/auth/slack/login/`, `/auth/slack/login/callback` 구조
|
||||||
- **UUID 생성**: UUID5 방식 구현됨 (namespace: 6ba7b810-9dad-11d1-80b4-00c04fd430c8)
|
- **localStorage**: `token` 키 통일, JWT 24시간, refresh 없음
|
||||||
|
- **OAuth**: auth-server 직접, API는 Gateway 경유
|
||||||
- **테이블**: slack_workspaces, slack_user_mapping 존재
|
- **테이블**: slack_workspaces, slack_user_mapping 존재
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -31,24 +32,37 @@
|
|||||||
Frontend → auth-server → Slack OIDC → UUID 생성 → JWT 발급
|
Frontend → auth-server → Slack OIDC → UUID 생성 → JWT 발급
|
||||||
```
|
```
|
||||||
|
|
||||||
**구현**:
|
**백엔드 엔드포인트**:
|
||||||
|
- `GET /auth/slack/login/` - OAuth 시작
|
||||||
|
- `GET /auth/slack/login/callback` - 토큰 교환, UUID 매핑, JWT 발급
|
||||||
|
- `GET /api/slack/mapping/{slack_user_id}` - UUID 조회
|
||||||
|
|
||||||
|
**구현 상세**:
|
||||||
1. Slack 앱 설정에서 "Sign in with Slack" 활성화 (OpenID Connect)
|
1. Slack 앱 설정에서 "Sign in with Slack" 활성화 (OpenID Connect)
|
||||||
- Redirect URL: `https://auth-server/auth/slack/callback`
|
- Redirect URL: `https://auth.ro-being.com/auth/slack/login/callback`
|
||||||
2. User Token 스코프: `openid`, `profile`, `email` (로그인용)
|
2. User Token 스코프: `openid`, `profile`, `email` (로그인용)
|
||||||
3. 콜백에서 `openid.connect.userInfo` 호출하여 사용자 정보 획득
|
3. 콜백에서 `openid.connect.userInfo` 호출하여 사용자 정보 획득
|
||||||
4. DB 저장: users 테이블에 slack_user_id, slack_team_id 추가
|
4. DB 저장: users 테이블 UUID, slack_user_mapping 매핑 저장
|
||||||
|
|
||||||
**주의**: `identity.*` 레거시 스코프는 사용 금지
|
**주의**: `identity.*` 레거시 스코프는 사용 금지
|
||||||
|
|
||||||
### Phase 2: Add to Slack (단기 3-5일)
|
### Phase 2: Add to Slack (단기 3-5일)
|
||||||
```
|
```
|
||||||
Frontend(레벨3) → auth-server → OAuth 2.0 → 봇 토큰 저장
|
Frontend(Slack 아이템 획득) → auth-server → OAuth 2.0 → 봇 토큰 저장
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Slack 패스포트 엔드포인트**:
|
||||||
|
- `GET /auth/slack/passport/` - 봇 설치 OAuth 시작
|
||||||
|
- `GET /auth/slack/passport/callback` - bot_token 저장
|
||||||
|
- `GET /auth/slack/passport/status` - 아이템 상태 확인
|
||||||
|
- `POST /auth/slack/passport/activate` - 아이템 장착
|
||||||
|
- `POST /auth/slack/passport/deactivate` - 아이템 해제
|
||||||
|
- `DELETE /auth/slack/passport/` - 아이템 취소
|
||||||
|
|
||||||
**구현**:
|
**구현**:
|
||||||
1. OAuth 2.0 플로우 (**별도**: Sign in with Slack과 분리)
|
1. OAuth 2.0 플로우 (**별도**: Sign in with Slack과 분리)
|
||||||
- Add to Slack 버튼: `https://slack.com/oauth/v2/authorize?...`
|
- Add to Slack 버튼: `https://slack.com/oauth/v2/authorize?...`
|
||||||
- 콜백: `/auth/slack/install/callback`
|
- 콜백: `/auth/slack/passport/callback`
|
||||||
2. Bot Token Scopes:
|
2. Bot Token Scopes:
|
||||||
```
|
```
|
||||||
읽기: channels:read, groups:read, channels:history,
|
읽기: channels:read, groups:read, channels:history,
|
||||||
@ -70,11 +84,9 @@ Slack Event → rb8001 → DB → SSE/WebSocket → Frontend
|
|||||||
- Request URL: `rb8001/slack/events`
|
- Request URL: `rb8001/slack/events`
|
||||||
- 이벤트: `message.channels`, `message.groups`, `message.im`, `message.mpim`, `app_mention`
|
- 이벤트: `message.channels`, `message.groups`, `message.im`, `message.mpim`, `app_mention`
|
||||||
- 쓰레드: `message.message_replied` 이벤트 존재하나 `thread_ts` 확인 권장
|
- 쓰레드: `message.message_replied` 이벤트 존재하나 `thread_ts` 확인 권장
|
||||||
2. **3초 규칙**: challenge 검증 및 이벤트 ACK 3초 내 필수
|
2. 채널 타입: C(공개), G(비공개/그룹), D(DM)
|
||||||
3. 채널 타입: C(공개), G(비공개/그룹), D(DM)
|
3. conversation_logs 저장: team_id, channel_id, thread_ts
|
||||||
4. conversation_logs 저장: team_id, channel_id, thread_ts
|
4. 초기 동기화: `conversations.history`로 백필
|
||||||
5. 초기 동기화: `conversations.history`로 백필
|
|
||||||
6. **Rate Limits**: Events API 시간당 30,000건 (초당 ~8건), Web API는 메서드별 상이
|
|
||||||
|
|
||||||
### Phase 4: 명령 처리 (중기 1-2주)
|
### Phase 4: 명령 처리 (중기 1-2주)
|
||||||
```
|
```
|
||||||
|
|||||||
@ -55,7 +55,7 @@ SELECT id::text as user_id # PostgreSQL UUID를 문자열로 변환
|
|||||||
```
|
```
|
||||||
**확인된 사항**:
|
**확인된 사항**:
|
||||||
- username → UUID 변환은 DB 조회로만 수행 (계산된 변환 없음)
|
- username → UUID 변환은 DB 조회로만 수행 (계산된 변환 없음)
|
||||||
- UUID4 형식만 사용 (UUID5 사용 안 함)
|
- UUID4 형식만 사용 (UUID 표준 형식)
|
||||||
- users 테이블에 username 없으면 변환 실패
|
- users 테이블에 username 없으면 변환 실패
|
||||||
|
|
||||||
### 2.3 rb8001 (51124) - 확인 완료
|
### 2.3 rb8001 (51124) - 확인 완료
|
||||||
|
|||||||
@ -63,7 +63,7 @@ workspace (로빙 1개)
|
|||||||
- [x] slack_user_mapping 테이블 활성화 (확인됨)
|
- [x] slack_user_mapping 테이블 활성화 (확인됨)
|
||||||
- [x] Gateway API /api/slack/{slack_id}/uuid 구현
|
- [x] Gateway API /api/slack/{slack_id}/uuid 구현
|
||||||
- [x] rb8001에서 Slack ID → UUID 변환 구현
|
- [x] rb8001에서 Slack ID → UUID 변환 구현
|
||||||
- [ ] robeing-monitor UUID5 제거 (선택사항)
|
- [ ] robeing-monitor UUID 변환 개선 (선택사항)
|
||||||
|
|
||||||
### Phase 3: 사용자 격리 ✅ 완료 (2025-08-28 18:15)
|
### Phase 3: 사용자 격리 ✅ 완료 (2025-08-28 18:15)
|
||||||
- [x] ChromaDB 사용자별 컬렉션 (rb8001_{user_uuid})
|
- [x] ChromaDB 사용자별 컬렉션 (rb8001_{user_uuid})
|
||||||
|
|||||||
@ -41,7 +41,7 @@
|
|||||||
### rb8001 ID 처리 ✅ 완료
|
### rb8001 ID 처리 ✅ 완료
|
||||||
| 기존 방식 | 개선 완료 | 상태 |
|
| 기존 방식 | 개선 완료 | 상태 |
|
||||||
|----------|----------|------|
|
|----------|----------|------|
|
||||||
| UUID5(DNS namespace, slack_id) | 51123 매핑 API 호출 | ✅ 완료 |
|
| UUID 생성(DNS namespace, slack_id) | 51123 매핑 API 호출 | ✅ 완료 |
|
||||||
| 로컬 변환으로 UUID 생성 | 실제 DB 매핑 사용 | ✅ 완료 |
|
| 로컬 변환으로 UUID 생성 | 실제 DB 매핑 사용 | ✅ 완료 |
|
||||||
| skill-email에 Slack ID 전달 | UUID 전달로 통일 | ✅ 완료 |
|
| skill-email에 Slack ID 전달 | UUID 전달로 통일 | ✅ 완료 |
|
||||||
|
|
||||||
@ -62,10 +62,10 @@ echo "JWT_SECRET_KEY=[REDACTED]" >> \
|
|||||||
docker restart skill-email
|
docker restart skill-email
|
||||||
```
|
```
|
||||||
|
|
||||||
### 단계 2: rb8001 UUID5 → API 매핑 전환
|
### 단계 2: rb8001 UUID → API 매핑 전환
|
||||||
```python
|
```python
|
||||||
# /rb8001/app/skills/email_integration.py 수정
|
# /rb8001/app/skills/email_integration.py 수정
|
||||||
# 기존: user_uuid = str(uuid.uuid5(namespace, user_id))
|
# 기존: user_uuid = str(uuid.uuid(namespace, user_id))
|
||||||
# 변경:
|
# 변경:
|
||||||
async def get_uuid_from_slack(slack_id: str):
|
async def get_uuid_from_slack(slack_id: str):
|
||||||
response = await httpx.get(
|
response = await httpx.get(
|
||||||
@ -88,7 +88,7 @@ await http_client.post(url, json=data, headers=headers)
|
|||||||
| 우선순위 | 작업 | 위치 | 상태 |
|
| 우선순위 | 작업 | 위치 | 상태 |
|
||||||
|---------|------|------|------|
|
|---------|------|------|------|
|
||||||
| 1 | ~~skill-email JWT_SECRET_KEY 설정~~ | ~~51124 서버~~ | ✅ 완료 |
|
| 1 | ~~skill-email JWT_SECRET_KEY 설정~~ | ~~51124 서버~~ | ✅ 완료 |
|
||||||
| 2 | ~~UUID5 → 매핑 API 전환~~ | ~~rb8001~~ | ✅ 완료 |
|
| 2 | ~~UUID → 매핑 API 전환~~ | ~~rb8001~~ | ✅ 완료 |
|
||||||
| 3 | ~~서비스 간 인증 헤더 추가~~ | ~~rb8001, skill-email~~ | ✅ 완료 |
|
| 3 | ~~서비스 간 인증 헤더 추가~~ | ~~rb8001, skill-email~~ | ✅ 완료 |
|
||||||
| 4 | Slack OAuth auth-server 경유 | auth-server, frontend | 🔜 향후 |
|
| 4 | Slack OAuth auth-server 경유 | auth-server, frontend | 🔜 향후 |
|
||||||
|
|
||||||
@ -110,7 +110,7 @@ curl http://192.168.219.45:9000/api/slack/mapping/U0925SXQFDK
|
|||||||
- rb8001, skill-email INTERNAL_API_KEY 설정 완료
|
- rb8001, skill-email INTERNAL_API_KEY 설정 완료
|
||||||
|
|
||||||
#### 2단계: ID 체계 통합 ✅
|
#### 2단계: ID 체계 통합 ✅
|
||||||
- rb8001 UUID5 → 51123 매핑 API 전환 완료
|
- rb8001 UUID → 51123 매핑 API 전환 완료
|
||||||
- 실제 DB 매핑으로 데이터 일관성 확보
|
- 실제 DB 매핑으로 데이터 일관성 확보
|
||||||
|
|
||||||
#### 3단계: 서비스 간 인증 ✅
|
#### 3단계: 서비스 간 인증 ✅
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user