371 lines
9.9 KiB
Markdown
371 lines
9.9 KiB
Markdown
# 회원 관리 및 인증 시스템 설정 가이드
|
|
|
|
## 📋 개요
|
|
|
|
부산교통공사 1호선 고장코드 시스템에 회원 관리 및 인증 기능이 추가되었습니다.
|
|
|
|
### 주요 기능
|
|
- ✅ **이메일 인증**: Supabase Auth를 사용한 이메일 기반 인증
|
|
- ✅ **도메인 제한**: humetro.busan.kr 도메인만 가입 가능
|
|
- ✅ **부서별 관리**: 부서 단위로 사용자 관리 및 권한 제어
|
|
- ✅ **세션 관리**: Flask 세션을 통한 로그인 상태 유지
|
|
|
|
---
|
|
|
|
## 🗄️ 1. 데이터베이스 설정
|
|
|
|
### 1.1 Supabase SQL 에디터에서 스키마 생성
|
|
|
|
`database_schema.sql` 파일의 내용을 Supabase SQL 에디터에서 실행하세요.
|
|
|
|
```bash
|
|
# 파일 위치
|
|
./database_schema.sql
|
|
```
|
|
|
|
이 스크립트는 다음 테이블을 생성합니다:
|
|
- **departments**: 부서 정보
|
|
- **users**: 사용자 정보
|
|
- **department_permissions**: 부서별 권한 (조회/수정/삭제)
|
|
- **audit_logs**: 감사 로그 (선택사항)
|
|
|
|
### 1.2 초기 부서 데이터
|
|
|
|
스크립트 실행 시 다음 부서가 자동으로 생성됩니다:
|
|
|
|
| 코드 | 부서명 | 설명 |
|
|
|------|--------|------|
|
|
| SPC | 신평차량 | 신평차량사업소 |
|
|
| NPC | 노포차량 | 노포차량사업소 |
|
|
| VHD | 차량처 | 차량처 |
|
|
|
|
> **참고**: 추가 부서가 필요한 경우 Supabase에서 직접 추가하거나 관리자 페이지를 통해 관리할 수 있습니다.
|
|
|
|
**추가 부서가 필요한 경우**:
|
|
```sql
|
|
INSERT INTO public.departments (code, name, description)
|
|
VALUES ('NEW001', '새로운부서', '부서 설명');
|
|
```
|
|
|
|
---
|
|
|
|
## 🔐 2. Supabase Auth 설정
|
|
|
|
### 2.1 Docker 기반 Supabase 환경
|
|
|
|
> ⚠️ **중요**: Docker 기반 Supabase를 사용하는 경우, 대시보드의 Authentication 설정이 제한적입니다.
|
|
>
|
|
> 따라서 **애플리케이션 레벨에서만 이메일 도메인 검증**을 수행합니다.
|
|
|
|
### 2.2 이메일 도메인 검증 (애플리케이션 레벨)
|
|
|
|
`auth.py` 모듈에서 자동으로 처리됩니다:
|
|
|
|
```python
|
|
# humetro.busan.kr 도메인만 허용
|
|
ALLOWED_EMAIL_DOMAIN = "humetro.busan.kr"
|
|
|
|
def validate_email(self, email: str) -> tuple[bool, str]:
|
|
domain = email.split('@')[1]
|
|
if domain != self.ALLOWED_EMAIL_DOMAIN:
|
|
return False, f"{self.ALLOWED_EMAIL_DOMAIN} 도메인의 이메일만 사용 가능합니다."
|
|
return True, "OK"
|
|
```
|
|
|
|
### 2.3 Supabase Auth 기본 설정 확인
|
|
|
|
Docker Supabase에서 확인할 사항:
|
|
- Supabase가 정상적으로 실행 중인지 확인
|
|
- Kong Gateway (기본 포트 8000)가 작동하는지 확인
|
|
- Auth 서비스가 활성화되어 있는지 확인
|
|
|
|
```bash
|
|
# Supabase 상태 확인
|
|
docker ps | grep supabase
|
|
```
|
|
|
|
---
|
|
|
|
## ⚙️ 3. 환경 변수 설정
|
|
|
|
### 3.1 Flask 백엔드 `.env` 파일 위치
|
|
|
|
> ⚠️ **중요**: `SECRET_KEY`는 **Flask 백엔드**의 `.env` 파일에 설정해야 합니다!
|
|
|
|
**파일 위치**: `/home/ckh08045/Tr_Code/.env` (app.py가 있는 디렉토리)
|
|
|
|
```bash
|
|
# Supabase 설정
|
|
SUPABASE_URL=http://localhost:8000
|
|
SUPABASE_ANON_KEY=your-anon-key-here
|
|
|
|
# Flask 세션 보안 키 (프로덕션에서는 반드시 변경!)
|
|
SECRET_KEY=your-secret-key-here-change-in-production
|
|
|
|
# Kong Basic Auth (선택사항)
|
|
SUPABASE_BASIC_USER=
|
|
SUPABASE_BASIC_PASSWORD=
|
|
```
|
|
|
|
### 3.2 SECRET_KEY 생성
|
|
|
|
Python으로 안전한 SECRET_KEY 생성:
|
|
|
|
```python
|
|
import secrets
|
|
print(secrets.token_hex(32))
|
|
```
|
|
|
|
생성된 키를 **Flask 백엔드 `.env`** 파일의 `SECRET_KEY`에 설정하세요.
|
|
|
|
### 3.3 프론트엔드와 백엔드 .env 구분
|
|
|
|
**Flask 백엔드 .env** (`/home/ckh08045/Tr_Code/.env`):
|
|
- `SUPABASE_URL`
|
|
- `SUPABASE_ANON_KEY`
|
|
- `SECRET_KEY` ← **여기에 설정!**
|
|
- `SUPABASE_BASIC_USER`
|
|
- `SUPABASE_BASIC_PASSWORD`
|
|
|
|
**TWA 프론트엔드 .env** (`/home/ckh08045/Tr_Code/twa-frontend/.env`):
|
|
- Vue.js 관련 설정
|
|
- API 엔드포인트 등
|
|
- `SECRET_KEY`는 **필요 없음**
|
|
|
|
---
|
|
|
|
## 🚀 4. 애플리케이션 실행
|
|
|
|
### 4.1 의존성 설치
|
|
|
|
```bash
|
|
pip install -r requirements.txt
|
|
```
|
|
|
|
### 4.2 서버 실행
|
|
|
|
```bash
|
|
python app.py
|
|
```
|
|
|
|
서버가 `http://localhost:5000`에서 실행됩니다.
|
|
|
|
---
|
|
|
|
## 📱 5. 사용 방법
|
|
|
|
### 5.1 회원가입
|
|
|
|
1. 브라우저에서 `http://localhost:5000` 접속
|
|
2. 자동으로 로그인 페이지로 리다이렉트됨
|
|
3. **회원가입** 버튼 클릭
|
|
4. 다음 정보 입력:
|
|
- 사번
|
|
- 이름
|
|
- 소속 부서 (드롭다운에서 선택)
|
|
- 이메일 (humetro.busan.kr 도메인만)
|
|
- 비밀번호 (최소 8자)
|
|
|
|
5. 회원가입 완료 후 이메일 인증 (Supabase Auth 설정에 따라)
|
|
|
|
### 5.2 로그인
|
|
|
|
1. 등록한 이메일과 비밀번호로 로그인
|
|
2. 로그인 성공 시 메인 페이지로 이동
|
|
3. 헤더에 사용자 이름과 사번 표시
|
|
|
|
### 5.3 로그아웃
|
|
|
|
- 헤더의 **로그아웃** 버튼 클릭
|
|
|
|
---
|
|
|
|
## 🔑 6. 권한 관리 (향후 확장)
|
|
|
|
### 6.1 부서별 권한 조회
|
|
|
|
```sql
|
|
SELECT d.name, dp.resource_type, dp.can_read, dp.can_write, dp.can_delete
|
|
FROM public.department_permissions dp
|
|
JOIN public.departments d ON dp.department_id = d.id
|
|
WHERE d.code = 'SPC';
|
|
```
|
|
|
|
### 6.2 권한 수정
|
|
|
|
```sql
|
|
UPDATE public.department_permissions
|
|
SET can_write = true
|
|
WHERE department_id = 1 AND resource_type = 'fault_code';
|
|
```
|
|
|
|
### 6.3 애플리케이션에서 권한 체크 (예시)
|
|
|
|
```python
|
|
def check_permission(user, resource_type, action):
|
|
"""
|
|
user: 현재 사용자 정보
|
|
resource_type: 'fault_code', 'signal', 'mmi_code'
|
|
action: 'read', 'write', 'delete'
|
|
"""
|
|
with build_pg_client() as c:
|
|
r = c.get(
|
|
"/department_permissions",
|
|
params={
|
|
"department_id": f"eq.{user['department_id']}",
|
|
"resource_type": f"eq.{resource_type}"
|
|
}
|
|
)
|
|
r.raise_for_status()
|
|
perms = r.json()
|
|
if perms:
|
|
return perms[0].get(f"can_{action}", False)
|
|
return False
|
|
```
|
|
|
|
---
|
|
|
|
## 📊 7. 데이터베이스 스키마
|
|
|
|
### 7.1 테이블 구조
|
|
|
|
#### departments (부서)
|
|
- `id` (PK): 부서 ID
|
|
- `code`: 부서 코드 (UNIQUE)
|
|
- `name`: 부서명
|
|
- `description`: 설명
|
|
- `is_active`: 활성화 여부
|
|
- `created_at`, `updated_at`: 타임스탬프
|
|
|
|
#### users (사용자)
|
|
- `id` (PK): 사용자 ID
|
|
- `auth_id`: Supabase Auth 사용자 ID (UNIQUE)
|
|
- `email`: 이메일 (UNIQUE)
|
|
- `employee_id`: 사번 (UNIQUE)
|
|
- `name`: 이름
|
|
- `department_id` (FK): 부서 ID
|
|
- `is_active`: 계정 활성화 여부
|
|
- `last_login_at`: 마지막 로그인 시각
|
|
- `created_at`, `updated_at`: 타임스탬프
|
|
|
|
#### department_permissions (부서별 권한)
|
|
- `id` (PK): 권한 ID
|
|
- `department_id` (FK): 부서 ID
|
|
- `resource_type`: 리소스 타입 ('fault_code', 'signal', 'mmi_code')
|
|
- `can_read`: 조회 권한
|
|
- `can_write`: 수정 권한
|
|
- `can_delete`: 삭제 권한
|
|
- `created_at`, `updated_at`: 타임스탬프
|
|
|
|
---
|
|
|
|
## 🔍 8. 트러블슈팅
|
|
|
|
### 8.1 로그인 실패
|
|
|
|
**증상**: "이메일 또는 비밀번호가 올바르지 않습니다."
|
|
|
|
**해결 방법**:
|
|
1. 이메일 주소가 `@humetro.busan.kr`로 끝나는지 확인
|
|
2. 비밀번호가 8자 이상인지 확인
|
|
3. Supabase Auth가 활성화되어 있는지 확인
|
|
4. `users` 테이블에 사용자가 존재하는지 확인:
|
|
```sql
|
|
SELECT * FROM public.users WHERE email = 'user@humetro.busan.kr';
|
|
```
|
|
|
|
### 8.2 회원가입 실패
|
|
|
|
**증상**: "회원가입에 실패했습니다."
|
|
|
|
**해결 방법**:
|
|
1. Supabase Auth가 활성화되어 있는지 확인
|
|
2. 이메일이 이미 등록되어 있는지 확인
|
|
3. 사번이 중복되지 않는지 확인
|
|
4. `departments` 테이블에 부서가 존재하는지 확인
|
|
|
|
### 8.3 부서 목록이 표시되지 않음
|
|
|
|
**증상**: 회원가입 페이지에서 부서 선택 드롭다운이 비어있음
|
|
|
|
**해결 방법**:
|
|
1. `database_schema.sql`이 정상적으로 실행되었는지 확인
|
|
2. `departments` 테이블에 데이터가 있는지 확인:
|
|
```sql
|
|
SELECT * FROM public.departments WHERE is_active = true;
|
|
```
|
|
|
|
### 8.4 세션이 유지되지 않음
|
|
|
|
**증상**: 페이지를 새로고침하면 로그인이 풀림
|
|
|
|
**해결 방법**:
|
|
1. `.env` 파일에 `SECRET_KEY`가 설정되어 있는지 확인
|
|
2. Flask 앱이 세션 쿠키를 설정할 수 있는지 확인 (HTTPS/HTTP 설정)
|
|
|
|
---
|
|
|
|
## 🛡️ 9. 보안 고려사항
|
|
|
|
### 9.1 프로덕션 체크리스트
|
|
|
|
- [ ] `SECRET_KEY` 변경 (절대 기본값 사용 금지)
|
|
- [ ] HTTPS 사용
|
|
- [ ] Supabase RLS(Row Level Security) 활성화
|
|
- [ ] 비밀번호 정책 강화 (대문자, 숫자, 특수문자 포함)
|
|
- [ ] 세션 타임아웃 설정
|
|
- [ ] CORS 설정 검토 (프로덕션에서는 특정 도메인만 허용)
|
|
- [ ] 로그 모니터링 (`audit_logs` 테이블 활용)
|
|
|
|
### 9.2 RLS 정책 (이미 적용됨)
|
|
|
|
`database_schema.sql`에 다음 RLS 정책이 포함되어 있습니다:
|
|
- 부서 목록은 모든 인증된 사용자가 조회 가능
|
|
- 사용자는 본인 정보만 조회/수정 가능
|
|
|
|
---
|
|
|
|
## 📚 10. 참고 자료
|
|
|
|
### 10.1 파일 구조
|
|
|
|
```
|
|
Tr_Code/
|
|
├── app.py # 메인 애플리케이션 (인증 라우트 포함)
|
|
├── auth.py # 인증 모듈 (AuthManager 클래스)
|
|
├── database_schema.sql # 데이터베이스 스키마
|
|
├── templates/
|
|
│ ├── index.html # 메인 페이지 (로그인 필요)
|
|
│ ├── login.html # 로그인 페이지
|
|
│ └── signup.html # 회원가입 페이지
|
|
└── .env # 환경 변수 설정
|
|
```
|
|
|
|
### 10.2 핵심 모듈
|
|
|
|
#### `auth.py` - AuthManager 클래스
|
|
- `validate_email()`: 이메일 도메인 검증
|
|
- `get_departments()`: 부서 목록 조회
|
|
- `signup_user()`: 회원가입 처리
|
|
- `login_user()`: 로그인 처리
|
|
- `logout_user()`: 로그아웃 처리
|
|
|
|
#### `app.py` - 인증 라우트
|
|
- `/auth/login`: 로그인 페이지 및 처리
|
|
- `/auth/signup`: 회원가입 페이지 및 처리
|
|
- `/auth/logout`: 로그아웃 처리
|
|
- `/`: 메인 페이지 (로그인 필요)
|
|
|
|
---
|
|
|
|
## 🤝 11. 문의 및 지원
|
|
|
|
시스템 관련 문의사항은 차량처 시스템 관리자에게 연락하세요.
|
|
|
|
---
|
|
|
|
**작성일**: 2024년 10월
|
|
**버전**: 1.0
|
|
**부산교통공사 차량처**
|
|
|