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:
@@ -39,12 +39,16 @@ const BansPage = {
|
||||
U.modal('添加封禁', `
|
||||
<form id="ban-form">
|
||||
<div class="grid-2"><div class="form-group"><label>玩家名 *</label><input id="ban-name" required></div><div class="form-group"><label>UID</label><input id="ban-uid"></div></div>
|
||||
<div class="grid-2"><div class="form-group"><label>来源</label><select id="ban-source"><option value="">未知</option><option value="netease">网易端</option><option value="skin">皮肤站</option></select></div><div class="form-group"><label>类型</label><select id="ban-type" onchange="BansPage.checkMinDuration()"><option value="ban">封禁</option><option value="mute">禁言</option><option value="warn">警告</option></select></div></div>
|
||||
<div class="grid-2"><div class="form-group"><label>来源</label><select id="ban-source"><option value="">未知</option></select></div><div class="form-group"><label>类型</label><select id="ban-type" onchange="BansPage.checkMinDuration()"><option value="ban">封禁</option><option value="mute">禁言</option><option value="warn">警告</option></select></div></div>
|
||||
<div class="grid-2"><div class="form-group"><label>时长</label><select id="ban-dur"><option value="">永久</option><option value="1天">1天</option><option value="3天">3天</option><option value="7天">7天</option><option value="30天">30天</option></select></div></div>
|
||||
<div class="form-group"><label>原因</label><textarea id="ban-reason" rows="2"></textarea></div>
|
||||
<div class="modal-f"><button type="button" class="btn btn-o" data-action="App:closeModal">取消</button><button type="submit" class="btn btn-p">添加</button></div>
|
||||
</form>
|
||||
`);
|
||||
U.sources().then(list => {
|
||||
const sel = document.getElementById('ban-source');
|
||||
if (sel) sel.innerHTML = '<option value="">未知</option>' + list.map(s => `<option value="${U.esc(s.code)}">${U.esc(s.label)}</option>`).join('');
|
||||
}).catch(()=>{});
|
||||
document.getElementById('ban-form').onsubmit = async e => {
|
||||
e.preventDefault();
|
||||
try {
|
||||
@@ -80,12 +84,16 @@ const BansPage = {
|
||||
U.modal('编辑封禁', `
|
||||
<form id="be-form">
|
||||
<div class="grid-2"><div class="form-group"><label>玩家名</label><input id="be-name" value="${name}"></div><div class="form-group"><label>UID</label><input id="be-uid" value="${uid}"></div></div>
|
||||
<div class="grid-2"><div class="form-group"><label>来源</label><select id="be-source"><option value="">未知</option><option value="netease" ${source==='netease'?'selected':''}>网易端</option><option value="skin" ${source==='skin'?'selected':''}>皮肤站</option></select></div><div class="form-group"><label>状态</label><select id="be-status"><option value="active" ${status==='active'?'selected':''}>生效中</option><option value="lifted" ${status==='lifted'?'selected':''}>已解除</option><option value="expired" ${status==='expired'?'selected':''}>已过期</option></select></div></div>
|
||||
<div class="grid-2"><div class="form-group"><label>来源</label><select id="be-source"><option value="">未知</option></select></div><div class="form-group"><label>状态</label><select id="be-status"><option value="active" ${status==='active'?'selected':''}>生效中</option><option value="lifted" ${status==='lifted'?'selected':''}>已解除</option><option value="expired" ${status==='expired'?'selected':''}>已过期</option></select></div></div>
|
||||
<div class="grid-2"><div class="form-group"><label>时长</label><input id="be-dur" value="${duration}"></div></div>
|
||||
<div class="form-group"><label>原因</label><textarea id="be-reason" rows="2">${reason}</textarea></div>
|
||||
<div class="modal-f"><button type="button" class="btn btn-o" data-action="App:closeModal">取消</button><button type="submit" class="btn btn-p">保存</button></div>
|
||||
</form>
|
||||
`);
|
||||
U.sources().then(list => {
|
||||
const sel = document.getElementById('be-source');
|
||||
if (sel) sel.innerHTML = '<option value="">未知</option>' + list.map(s => `<option value="${U.esc(s.code)}" ${s.code===source?'selected':''}>${U.esc(s.label)}</option>`).join('');
|
||||
}).catch(()=>{});
|
||||
document.getElementById('be-form').onsubmit = async e => {
|
||||
e.preventDefault();
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user