Add authenticated login and SSO protection

This commit is contained in:
inman
2026-05-29 15:54:13 +08:00
parent e36f28a668
commit 0648874801
50 changed files with 1853 additions and 63 deletions

View File

@@ -238,6 +238,70 @@
| 2026-05-29 | Browser REPL variable names collided across verification cells | 1 | Reused or renamed persistent variables instead of redeclaring constants |
| 2026-05-29 | White logo required a dark frame on the light topbar and looked off-brand | 1 | Switched to black/blue logo, generated a transparent cropped asset, and removed frame styling |
## Session: 2026-05-29 - Account Login and SSO Protection
### Phase 13: Account Login and SSO Protection
- **Status:** in_progress
- Actions taken:
- Restored existing planning context and started a new Phase 13 for account login.
- Read the provided SSO integration guide.
- Confirmed the app currently has no login middleware/session helper and uses a fixed `demo-merchant` owner for first-party data.
- Started tracing routes and data access boundaries.
- Inspected first-party asset, generation, settings, health, upload, and file-serving routes.
- Confirmed public API v1 and worker routes use separate token mechanisms and should be preserved.
- Added auth config parsing, signed session cookies, OAuth2 authorize/callback/logout routes, JWT/JWKS verification, and current-user helpers.
- Added login page and topbar login/user/logout state.
- Added middleware protection for Web pages, first-party APIs, and local file-serving routes.
- Threaded authenticated owner IDs through first-party asset and generation routes.
- Added local file ownership checks through `storagePath`.
- Added SSO settings fields, health/settings status, env examples, README docs, deployment notes, and focused auth tests.
- Ran `npm test`: 8 files / 25 tests passed.
- Ran `npm run build`: production build passed with middleware and auth routes included.
- Browser-checked `/create` and `/auth/login` at desktop and 390px widths: no horizontal overflow, login config-missing state renders correctly.
- Verified forced-auth middleware behavior with a temporary dev server: `/create` redirects to `/auth/login`, first-party `/api/assets` returns 503 when auth is missing config, and `/api/v1/openapi.json` remains public.
- **Status:** complete
## Test Results - Account Login and SSO Protection
| Test | Input | Expected | Actual | Status |
|------|-------|----------|--------|--------|
| Unit tests | `npm test` | All tests pass | 8 files / 25 tests passed | pass |
| Production build | `npm run build` | Build succeeds | Build succeeded | pass |
| Browser layout | `/create`, `/auth/login`, 1280px and 390px | No horizontal overflow | Confirmed | pass |
| Middleware redirect | `GET /create` with `ZHINIAN_AUTH_REQUIRED=1` and missing auth config | Redirect to login | 307 to `/auth/login?next=%2Fcreate&error=auth_not_configured` | pass |
| First-party API guard | `GET /api/assets` with required auth and missing config | 503 JSON | `{"error":"认证配置不完整。"}` | pass |
| Public API preservation | `GET /api/v1/openapi.json` with required auth and missing config | 200 | 200 OK | pass |
## Error Log - Account Login and SSO Protection
| Timestamp | Error | Attempt | Resolution |
|-----------|-------|---------|------------|
| 2026-05-29 | zsh expanded unquoted `[id]` dynamic route paths again while reading route files | 1 | Re-ran the reads with single-quoted route paths |
| 2026-05-29 | `npm run build` failed because DOM `JsonWebKey` type does not include JWKS `kid` | 1 | Switched verifier typing to Node crypto `JsonWebKey` with a local `kid` extension |
## Session: 2026-05-29 - Password Captcha Login
### Phase 14: Password Captcha Login
- **Status:** complete
- Actions taken:
- Safely inspected the provided captcha and password grant response shape without printing tokens.
- Added `components/auth-login-panel.tsx` for account/password/captcha login on `/auth/login`.
- Added `/api/auth/captcha` to proxy image captcha requests to the auth service.
- Added `/api/auth/password` to call password grant server-side, verify the returned JWT, and set the same signed session cookie.
- Kept the original OAuth Authorization Code link as a secondary login option.
- Updated README, Chinese README, and deployment docs.
- Ran `npm test`: 8 files / 25 tests passed.
- Ran `npm run build`: production build passed.
- Restarted the dev server on `127.0.0.1:3001`.
- Browser-tested password captcha login with the user-provided test account; login reached `/create`, the topbar showed the authenticated username, and logout returned to `/auth/login?loggedOut=1`.
## Test Results - Password Captcha Login
| Test | Input | Expected | Actual | Status |
|------|-------|----------|--------|--------|
| Captcha endpoint | `${AUTH_BASE}/code/image?randomStr=...` | Image response | PNG 100x40 | pass |
| Password grant | Provided password grant sample | JWT token response | 200 with access/refresh tokens, sanitized in logs | pass |
| Local password login API | `POST /api/auth/password` | Signed session cookie | 200 and `zhinian_session` set | pass |
| Browser login | `/auth/login` form | Redirect to `/create` | `/create` rendered with authenticated username in topbar | pass |
| Logout | Click topbar logout | Return to login | `/auth/login?loggedOut=1` | pass |
## Session: 2026-05-29 - Server One-Command Deployment Support
### Docker and Script Deployment
@@ -316,6 +380,26 @@
- Desktop and mobile screenshots showed the create-page controls fitting cleanly.
- Browser page errors list was empty.
## Session: 2026-05-29 - Standalone Login Page Polish
### Implementation
- **Status:** complete
- Actions taken:
- Updated the app shell so `/auth/*` pages render without the shared topbar and skip link.
- Reworked `/auth/login` into a standalone branded surface with logo, platform name, and account/password/captcha login box.
- Removed the visible `统一认证中心` login action from the login page.
- Kept login motion on the existing GSAP helper layer for scoped reveal and feedback animation.
### Verification
- **Status:** complete
- Results:
- In-app browser mobile-width check confirmed no topbar, no SSO link, logo/platform name present, login panel present, and no horizontal overflow.
- Browser viewport checks at 1280x800 and 390x844 confirmed the same layout invariants.
- `npm test`: 8 files / 25 tests passed.
- `npm run build`: production build succeeded and included `/auth/login`.
- After restarting the dev server on `127.0.0.1:3001`, the login page still rendered without the topbar or SSO entry.
- Earlier auth verification for this session passed form login, redirect to `/create`, and logout back to `/auth/login`.
## Error Log - Server Deployment Support
| Timestamp | Error | Attempt | Resolution |
|-----------|-------|---------|------------|