# User Authentication & Authorization ## Purpose 使用者認證與授權系統,透過外部認證 API 進行身份驗證,提供細部權限控制。 ## Requirements ### Requirement: API-Based Authentication 系統 SHALL 限定使用外部認證 API (https://pj-auth-api.vercel.app) 進行登入認證,不支援其他認證方式。 #### Scenario: API 登入成功 - **GIVEN** 使用者擁有有效的企業帳號 - **WHEN** 使用者透過前端提交憑證 - **THEN** 系統呼叫 https://pj-auth-api.vercel.app 驗證憑證 - **AND** 驗證成功後建立 session 並回傳 JWT token #### Scenario: API 登入失敗 - **GIVEN** 使用者提供無效的憑證 - **WHEN** 使用者嘗試登入 - **THEN** 認證 API 回傳錯誤 - **AND** 系統拒絕登入並顯示錯誤訊息 - **AND** 記錄失敗的登入嘗試 #### Scenario: 認證 API 無法連線 - **GIVEN** 認證 API 服務無法連線 - **WHEN** 使用者嘗試登入 - **THEN** 系統顯示服務暫時無法使用的訊息 - **AND** 記錄連線失敗事件 ### Requirement: System Administrator 系統 SHALL 預設一個系統管理員帳號,擁有所有權限。系統管理員帳號必須存在於外部認證系統,且登入流程仍需透過外部認證 API;不允許本地繞過認證。 #### Scenario: 預設管理員帳號 - **GIVEN** 系統初始化完成 - **WHEN** 系統啟動 - **THEN** 存在預設管理員帳號 `ymirliu@panjit.com.tw` - **AND** 該帳號擁有 `super_admin` 角色 - **AND** 該帳號不可被刪除或降級 #### Scenario: 管理員登入流程 - **GIVEN** 管理員帳號 `ymirliu@panjit.com.tw` 需要登入 - **WHEN** 管理員提交憑證 - **THEN** 系統仍需呼叫 https://pj-auth-api.vercel.app 驗證 - **AND** 不存在任何本地繞過認證的機制 - **AND** 驗證成功後才授予 `super_admin` 權限 #### Scenario: 管理員全域權限 - **GIVEN** 管理員帳號 `ymirliu@panjit.com.tw` 已通過 API 認證並登入 - **WHEN** 管理員存取任何資源 - **THEN** 系統允許存取,無視部門隔離限制 ### Requirement: Role-Based Access Control 系統 SHALL 支援基於角色的存取控制 (RBAC)。 #### Scenario: 角色權限檢查 - **GIVEN** 使用者被指派特定角色 (如:工程師、主管、PMO) - **WHEN** 使用者嘗試存取受保護的資源 - **THEN** 系統根據角色權限決定是否允許存取 #### Scenario: 角色指派 - **GIVEN** 管理員擁有使用者管理權限 - **WHEN** 管理員為使用者指派角色 - **THEN** 系統更新使用者的角色設定 - **AND** 新權限立即生效 ### Requirement: Department Isolation 系統 SHALL 實施部門級別的資料隔離,確保跨部門資料安全。 #### Scenario: 部門資料隔離 - **GIVEN** 使用者屬於研發部門 - **WHEN** 使用者嘗試存取廠務部門的專案 - **THEN** 系統拒絕存取並顯示無權限訊息 #### Scenario: 跨部門專案存取 - **GIVEN** 專案被設定為跨部門可見 - **WHEN** 不同部門的使用者嘗試存取該專案 - **THEN** 系統根據專案的 Security_Level 設定決定是否允許存取 ### Requirement: Session Management 系統 SHALL 管理使用者 session,包含過期與登出機制。 #### Scenario: Session 過期 - **GIVEN** 使用者已登入系統 - **WHEN** Session 超過設定的有效期限 - **THEN** 系統自動使 session 失效 - **AND** 使用者需重新登入 #### Scenario: 主動登出 - **GIVEN** 使用者已登入系統 - **WHEN** 使用者執行登出操作 - **THEN** 系統銷毀 session 並清除 token ### Requirement: API Rate Limiting The system SHALL implement rate limiting to protect against brute force attacks and DoS attempts. #### Scenario: Login rate limit enforcement - **GIVEN** a client IP has made 5 login attempts within 1 minute - **WHEN** the client attempts another login - **THEN** the system returns HTTP 429 Too Many Requests - **AND** the response includes a Retry-After header #### Scenario: Rate limit window reset - **GIVEN** a client has exceeded the rate limit - **WHEN** the rate limit window expires (1 minute) - **THEN** the client can make new requests #### Scenario: Rate limit per IP - **GIVEN** rate limiting is IP-based - **WHEN** different IPs make requests - **THEN** each IP has its own rate limit counter ### Requirement: Comprehensive API Rate Limiting The system SHALL enforce rate limits on all sensitive API endpoints to prevent abuse and ensure service availability. #### Scenario: Task creation rate limit exceeded - **WHEN** user exceeds 60 task creation requests per minute - **THEN** system returns 429 Too Many Requests - **THEN** response includes Retry-After header #### Scenario: Report generation rate limit exceeded - **WHEN** user exceeds 5 report generation requests per minute - **THEN** system returns 429 Too Many Requests - **THEN** response includes rate limit headers #### Scenario: Rate limit headers provided - **WHEN** user makes any rate-limited API request - **THEN** response includes X-RateLimit-Limit header - **THEN** response includes X-RateLimit-Remaining header - **THEN** response includes X-RateLimit-Reset header #### Scenario: Rate limit window reset - **WHEN** rate limit window expires - **THEN** user can make requests again up to the limit - **THEN** X-RateLimit-Remaining resets to maximum ### Requirement: Input Length Validation The system SHALL enforce maximum length limits on all user-provided string inputs to prevent DoS attacks and database overflow. #### Scenario: Task title exceeds maximum length - **WHEN** user submits a task with title longer than 500 characters - **THEN** system returns 422 Validation Error with descriptive message #### Scenario: Description field within limits - **WHEN** user submits content with description under 10000 characters - **THEN** system accepts the input and processes normally ### Requirement: Secure WebSocket Authentication The system SHALL authenticate WebSocket connections without exposing tokens in URL query parameters. #### Scenario: WebSocket connection with token in first message - **WHEN** client connects to WebSocket endpoint without a query token - **THEN** server waits for authentication message containing JWT token - **THEN** server validates token before accepting further messages - **THEN** server sends an authentication acknowledgment message #### Scenario: WebSocket connection with invalid token - **WHEN** client sends an invalid or expired token - **THEN** server sends an error message indicating invalid or expired token - **THEN** server closes the connection with an authentication error code #### Scenario: WebSocket connection timeout without authentication - **WHEN** client connects but does not send authentication within 10 seconds - **THEN** server closes the connection with appropriate error code ### Requirement: Path Traversal Protection The system SHALL prevent file path traversal attacks by validating all file paths resolve within the designated storage directory. #### Scenario: Path traversal attempt detected - **WHEN** request contains file path with "../" or absolute path outside storage - **THEN** system rejects request and logs security warning - **THEN** system returns 403 Forbidden error #### Scenario: Valid file path within storage - **WHEN** request contains valid relative file path - **THEN** system resolves path and verifies it is within storage directory - **THEN** system processes file operation normally ### Requirement: JWT Secret Validation The system SHALL validate JWT secret key strength on startup. #### Scenario: Weak secret rejected - **WHEN** the configured JWT secret is less than 32 characters - **THEN** the system SHALL log a critical warning - **AND** optionally refuse to start in production mode #### Scenario: Low entropy secret warning - **WHEN** the JWT secret has low entropy (repeating patterns, common words) - **THEN** the system SHALL log a security warning ### Requirement: CSRF Protection The system SHALL protect sensitive state-changing operations with CSRF tokens. #### Scenario: CSRF token required for password change - **WHEN** a user attempts to change their password - **AND** the request does not include a valid CSRF token - **THEN** the request SHALL be rejected with 403 Forbidden #### Scenario: CSRF token required for account deletion - **WHEN** a user attempts to delete their account or resources - **AND** the request does not include a valid CSRF token - **THEN** the request SHALL be rejected with 403 Forbidden #### Scenario: Valid CSRF token accepted - **WHEN** a state-changing request includes a valid CSRF token - **THEN** the request SHALL proceed normally ## Data Model ``` pjctrl_users ├── id: UUID (PK) ├── email: VARCHAR(200) UNIQUE ├── name: VARCHAR(200) ├── department_id: UUID (FK) ├── role_id: UUID (FK) ├── skills: JSON ├── capacity: DECIMAL (週工時上限) ├── is_active: BOOLEAN ├── is_system_admin: BOOLEAN DEFAULT false (不可修改的系統管理員標記) ├── created_at: TIMESTAMP └── updated_at: TIMESTAMP pjctrl_departments ├── id: UUID (PK) ├── name: VARCHAR(100) ├── parent_id: UUID (FK, self-reference) └── created_at: TIMESTAMP pjctrl_roles ├── id: UUID (PK) ├── name: VARCHAR(50) ├── permissions: JSON ├── is_system_role: BOOLEAN DEFAULT false └── created_at: TIMESTAMP ``` ## Default Data (Seed) ```sql -- 預設系統管理員角色 INSERT INTO pjctrl_roles (id, name, permissions, is_system_role) VALUES ('00000000-0000-0000-0000-000000000001', 'super_admin', '{"all": true}', true); -- 預設系統管理員帳號 INSERT INTO pjctrl_users (id, email, name, role_id, is_active, is_system_admin) VALUES ('00000000-0000-0000-0000-000000000001', 'ymirliu@panjit.com.tw', 'System Administrator', '00000000-0000-0000-0000-000000000001', true, true); ``` ## External Dependencies - **Authentication API**: https://pj-auth-api.vercel.app (唯一認證方式) ## Authentication Flow ``` ┌─────────┐ ┌─────────────┐ ┌──────────────────────────┐ │ User │────▶│ Frontend │────▶│ pj-auth-api.vercel.app │ └─────────┘ └─────────────┘ └──────────────────────────┘ │ │ │◀────── JWT Token ───────│ │ ▼ ┌─────────────┐ │ Backend │ (驗證 JWT, 建立 Session) └─────────────┘ ```