# ISO 27001 系統 - 認證系統設定指南

## 後端認證系統已完成

### 完成項目

#### 1. 使用者模型 (User Model)
- ✅ 自訂使用者模型 (extends AbstractUser)
- ✅ 6 種角色系統：超級管理員、組織管理員、資安人員、稽核人員、一般員工、唯讀使用者
- ✅ 帳號鎖定機制 (5 次失敗後鎖定 30 分鐘)
- ✅ MFA 支援 (預留欄位)
- ✅ 密碼歷史記錄
- ✅ 登入歷史追蹤

#### 2. JWT 認證
- ✅ Access Token (2 小時有效期)
- ✅ Refresh Token (7 天有效期)
- ✅ Token 刷新機制
- ✅ Token 自動輪換

#### 3. API 端點

##### 認證相關
```
POST   /api/auth/login/              - 使用者登入
POST   /api/auth/logout/             - 使用者登出
POST   /api/auth/refresh-token/      - 刷新 Token
```

##### 使用者管理
```
GET    /api/auth/users/              - 取得使用者列表
POST   /api/auth/users/              - 建立新使用者
GET    /api/auth/users/{id}/         - 取得使用者詳情
PATCH  /api/auth/users/{id}/         - 更新使用者
DELETE /api/auth/users/{id}/         - 刪除使用者
GET    /api/auth/users/me/           - 取得當前使用者資訊
POST   /api/auth/users/change_password/ - 變更密碼
POST   /api/auth/users/{id}/reset_password/ - 重置密碼 (管理員)
POST   /api/auth/users/{id}/lock/    - 鎖定使用者 (管理員)
POST   /api/auth/users/{id}/unlock/  - 解鎖使用者 (管理員)
```

##### 登入歷史
```
GET    /api/auth/login-history/      - 取得登入歷史
GET    /api/auth/login-history/{id}/ - 取得登入記錄詳情
```

#### 4. 權限控制
- ✅ 角色基礎權限控制 (RBAC)
- ✅ 自訂權限檢查方法
- ✅ API 權限驗證

## 設定步驟

### 1. 安裝相依套件

```bash
cd backend
pip install -r requirements.txt
```

### 2. 設定環境變數

編輯 `.env` 檔案：

```env
SECRET_KEY=your-secret-key-here
DEBUG=True
DATABASE_URL=postgresql://iso27001_user:iso27001_pass@localhost:5432/iso27001_db
REDIS_URL=redis://localhost:6379/0
ALLOWED_HOSTS=localhost,127.0.0.1
CORS_ALLOWED_ORIGINS=http://localhost:3000,http://127.0.0.1:3000
```

### 3. 執行資料庫遷移

```bash
# 建立 accounts app 的遷移檔案
python3 manage.py makemigrations accounts

# 執行所有遷移
python3 manage.py migrate

# 建立超級使用者
python3 manage.py createsuperuser
```

### 4. 測試 API

#### 登入
```bash
curl -X POST http://localhost:8000/api/auth/login/ \
  -H "Content-Type: application/json" \
  -d '{
    "username": "admin",
    "password": "your_password"
  }'
```

回應：
```json
{
  "message": "登入成功",
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
  "refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
  "user": {
    "id": "uuid-here",
    "username": "admin",
    "email": "admin@example.com",
    "role": "super_admin",
    ...
  }
}
```

#### 取得當前使用者資訊
```bash
curl -X GET http://localhost:8000/api/auth/users/me/ \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```

#### 變更密碼
```bash
curl -X POST http://localhost:8000/api/auth/users/change_password/ \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "old_password": "old_pass",
    "new_password": "NewP@ssw0rd123",
    "new_password_confirm": "NewP@ssw0rd123"
  }'
```

#### 刷新 Token
```bash
curl -X POST http://localhost:8000/api/auth/refresh-token/ \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "refresh_token": "YOUR_REFRESH_TOKEN"
  }'
```

## 安全功能

### 1. 帳號鎖定機制
- 連續 5 次登入失敗 → 鎖定 30 分鐘
- 管理員可手動鎖定/解鎖帳號

### 2. 密碼安全
- Django 內建密碼驗證器
- 最小長度檢查
- 常見密碼檢查
- 與使用者屬性相似度檢查
- 全數字密碼檢查

### 3. 登入歷史
- 記錄所有登入嘗試
- 記錄 IP 位址、User Agent
- 記錄登入成功/失敗
- 記錄登出時間

### 4. Token 安全
- Access Token：2 小時有效期
- Refresh Token：7 天有效期
- Token 輪換機制
- 使用後的 Refresh Token 列入黑名單

## 角色權限說明

### 超級管理員 (super_admin)
- 完整系統權限
- 可管理所有使用者
- 可查看所有資料

### 組織管理員 (org_admin)
- 組織內完整權限
- 可管理組織內使用者
- 可核准文件與資產

### 資安人員 (security_officer)
- 可查看、新增、修改、刪除
- 可管理資安相關功能
- 無核准權限

### 稽核人員 (auditor)
- 唯讀查看權限
- 可進行稽核作業

### 一般員工 (employee)
- 可查看授權資料
- 可新增和修改自己的資料

### 唯讀使用者 (readonly)
- 僅可查看授權資料

## Django Admin 管理

訪問 http://localhost:8000/admin/ 可以：

- 管理使用者帳號
- 查看登入歷史
- 查看密碼歷史
- 手動鎖定/解鎖帳號
- 重置使用者密碼

## 前端整合建議

### 1. Token 儲存
```javascript
// 儲存 Token
localStorage.setItem('access_token', response.data.access_token);
localStorage.setItem('refresh_token', response.data.refresh_token);
localStorage.setItem('user', JSON.stringify(response.data.user));

// 讀取 Token
const accessToken = localStorage.getItem('access_token');
```

### 2. Axios 攔截器
```javascript
import axios from 'axios';

// 請求攔截器 - 自動添加 Token
axios.interceptors.request.use(
  config => {
    const token = localStorage.getItem('access_token');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  error => Promise.reject(error)
);

// 回應攔截器 - 處理 Token 過期
axios.interceptors.response.use(
  response => response,
  async error => {
    if (error.response?.status === 401) {
      // Token 過期，嘗試刷新
      const refreshToken = localStorage.getItem('refresh_token');
      if (refreshToken) {
        try {
          const response = await axios.post('/api/auth/refresh-token/', {
            refresh_token: refreshToken
          });
          localStorage.setItem('access_token', response.data.access_token);
          // 重試原請求
          error.config.headers.Authorization = `Bearer ${response.data.access_token}`;
          return axios.request(error.config);
        } catch {
          // 刷新失敗，登出
          localStorage.clear();
          window.location.href = '/login';
        }
      }
    }
    return Promise.reject(error);
  }
);
```

### 3. React 路由保護
```javascript
import { Navigate } from 'react-router-dom';

function ProtectedRoute({ children }) {
  const token = localStorage.getItem('access_token');
  
  if (!token) {
    return <Navigate to="/login" replace />;
  }
  
  return children;
}
```

## 下一步

1. 實作前端登入頁面
2. 實作前端 Token 管理
3. 實作路由權限保護
4. 整合現有資產管理 API 的權限控制

## 測試建議

### 單元測試

```python
# backend/accounts/tests.py

from django.test import TestCase
from django.contrib.auth import get_user_model
from rest_framework.test import APIClient
from rest_framework import status

User = get_user_model()


class AuthenticationTestCase(TestCase):
    def setUp(self):
        self.client = APIClient()
        self.user = User.objects.create_user(
            username='testuser',
            email='test@example.com',
            password='testpass123',
            role='employee'
        )
    
    def test_login_success(self):
        """測試登入成功"""
        response = self.client.post('/api/auth/login/', {
            'username': 'testuser',
            'password': 'testpass123'
        })
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIn('access_token', response.data)
        self.assertIn('refresh_token', response.data)
    
    def test_login_fail(self):
        """測試登入失敗"""
        response = self.client.post('/api/auth/login/', {
            'username': 'testuser',
            'password': 'wrongpass'
        })
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
    
    def test_account_lockout(self):
        """測試帳號鎖定"""
        # 連續 5 次登入失敗
        for i in range(5):
            self.client.post('/api/auth/login/', {
                'username': 'testuser',
                'password': 'wrongpass'
            })
        
        # 第 6 次應該被鎖定
        response = self.client.post('/api/auth/login/', {
            'username': 'testuser',
            'password': 'testpass123'
        })
        self.assertIn('鎖定', response.data['non_field_errors'][0])
```

執行測試：
```bash
python3 manage.py test accounts
```

## 常見問題

### Q: 如何重置被鎖定的帳號？

A: 使用 Django Admin 或 API：
```bash
curl -X POST http://localhost:8000/api/auth/users/{user_id}/unlock/ \
  -H "Authorization: Bearer ADMIN_TOKEN"
```

### Q: Token 過期後如何處理？

A: 使用 Refresh Token 取得新的 Access Token

### Q: 如何變更密碼政策？

A: 修改 `settings.py` 中的 `AUTH_PASSWORD_VALIDATORS`

---

**完成時間**: 2025-10-31

**狀態**: Task 1.3.1 後端認證系統 ✅ 完成
