refactor: session-based external auth, dynamic sources, drop netease UID

Auth (external API):
- ID: 16-digit random (non-sequential); Secret: SeaReport- + 32 hex
- POST /auth/session: ID+Secret -> Bearer SESSION (24h, single-session,
  old session invalidated on re-issue, disabled client invalidates)
- clientAuth now validates Bearer SESSION via api_sessions JOIN api_clients

Sources (dynamic, no default, open-source friendly):
- sources table + CRUD route (/api/sources, owner; delete guarded by usage)
- users/user_identities.source ENUM -> VARCHAR, seeded netease/skin
- register/admin create/identity bind: validate against enabled sources
- UI: 来源管理 page; source dropdowns loaded dynamically everywhere
  (register, dashboard identity, users admin, bans), labels dynamic

UID removal:
- game_uid/reporter_game_uid no longer required (db default '', validations
  dropped, frontend fields optional)

Docs: EXTERNAL-API.md session flow + new credential format; API.md updated
Verified: 37 checks (syntax, session logic, source CRUD, UID removal, docs)
This commit is contained in:
2026-08-19 20:08:06 +08:00
parent 6056153f57
commit 65edbaf157
19 changed files with 497 additions and 103 deletions

View File

@@ -129,6 +129,7 @@ function loadBusinessRoutes() {
businessRouter.use('/features', methodGuard(['GET','POST','PUT','DELETE']), generalLimiter, require('./routes/features'));
businessRouter.use('/bans', methodGuard(['GET','POST','PUT','DELETE']), generalLimiter, require('./routes/bans'));
businessRouter.use('/logs', methodGuard(['GET']), generalLimiter, require('./routes/logs'));
businessRouter.use('/sources', methodGuard(['GET','POST','PUT','DELETE']), generalLimiter, require('./routes/sources'));
businessRouter.use('/external', require('./routes/external'));
businessRouter.get('/verify', (req, res) => res.redirect(`/#/verify?token=${req.query.token}`));