diff --git a/backend/routes/auth.js b/backend/routes/auth.js index ae37515..5b3d069 100644 --- a/backend/routes/auth.js +++ b/backend/routes/auth.js @@ -118,13 +118,15 @@ router.post('/register', validateLengths({ } catch {} const hashed = await bcrypt.hash(password, 10); + // 游戏UID为内置参数: 不接收玩家输入, 由系统自动生成 + const builtinUid = 'U' + uuid().replace(/-/g, '').slice(0, 12).toUpperCase(); const r = await query( 'INSERT INTO users(username, password, email, game_name, game_uid, active, email_verified, source) VALUES (?,?,?,?,?,?,?,?)', - [username, hashed, email, game_name, game_uid||'', 1, 1, source || ''] + [username, hashed, email, game_name, builtinUid, 1, 1, source || ''] ); try { await query('INSERT INTO user_identities(user_id, source, game_name, game_uid) VALUES (?,?,?,?)', - [r.insertId, source || '', game_name, game_uid || '']); + [r.insertId, source || '', game_name, builtinUid]); } catch {} res.status(201).json({ message: '注册成功,请登录' }); } catch (err) { @@ -233,7 +235,8 @@ router.post('/identities', authenticate, async (req, res) => { if (dupName) return res.status(400).json({ error: '该游戏名已绑定其他账号' }); const r = await query('INSERT INTO user_identities(user_id, source, game_name, game_uid) VALUES (?,?,?,?)', - [req.user.id, source || '', game_name, game_uid || '']); + // 游戏UID为内置参数: 不接收玩家输入, 由系统自动生成 + [req.user.id, source || '', game_name, 'U' + uuid().replace(/-/g, '').slice(0, 12).toUpperCase()]); res.status(201).json({ id: r.insertId, message: '绑定成功' }); } catch (err) { console.error('[auth]', err); diff --git a/backend/routes/external.js b/backend/routes/external.js index 5b8b4dc..f37701e 100644 --- a/backend/routes/external.js +++ b/backend/routes/external.js @@ -166,14 +166,16 @@ router.post('/auth/register', async (req, res) => { const hashed = bcrypt.hashSync(password, 10); const verifyToken = uuid(); - const r = await query('INSERT INTO users(username,password,email,game_name,game_uid,verify_token,verify_expires,source) VALUES (?,?,?,?,?,?,DATE_ADD(NOW(), INTERVAL 24 HOUR),?)', [username, hashed, email, game_name, game_uid || '', verifyToken, source || '']); + // 游戏UID为内置参数: 不接收客户端输入, 由系统自动生成 + const builtinUid = 'U' + crypto.randomBytes(6).toString('hex').toUpperCase(); + const r = await query('INSERT INTO users(username,password,email,game_name,game_uid,verify_token,verify_expires,source) VALUES (?,?,?,?,?,?,DATE_ADD(NOW(), INTERVAL 24 HOUR),?)', [username, hashed, email, game_name, builtinUid, verifyToken, source || '']); try { await query('INSERT INTO user_identities(user_id, source, game_name, game_uid) VALUES (?,?,?,?)', - [r.insertId, source || '', game_name, game_uid || '']); + [r.insertId, source || '', game_name, builtinUid]); } catch {} const site = await getRow("SELECT v FROM settings WHERE k='site_url'"); - const sent = await sendEmail(email, 'verify_email', { username, game_name, game_uid, verify_link: `${site?.v||'http://localhost:3100'}#/verify?token=${verifyToken}` }); + const sent = await sendEmail(email, 'verify_email', { username, game_name, game_uid: builtinUid, verify_link: `${site?.v||'http://localhost:3100'}#/verify?token=${verifyToken}` }); if (!sent) { await query('UPDATE users SET email_verified=1,active=1,verify_token=NULL WHERE username=?', [username]); diff --git a/backend/routes/install.js b/backend/routes/install.js index 026e845..91ae6bf 100644 --- a/backend/routes/install.js +++ b/backend/routes/install.js @@ -85,9 +85,11 @@ router.post('/complete', async (req, res) => { await initSchema(conn); const hashed = bcrypt.hashSync(admin_password, 10); + // 游戏UID为内置参数: 不接收输入, 由系统自动生成 + const builtinUid = 'U' + crypto.randomBytes(6).toString('hex').toUpperCase(); await conn.query( 'INSERT INTO users(username, password, email, game_name, game_uid, role, active, email_verified) VALUES (?,?,?,?,?,?,1,1)', - [admin_username, hashed, admin_email, admin_game_name || admin_username, admin_game_uid || 'OWNER001', 'owner'] + [admin_username, hashed, admin_email, admin_game_name || admin_username, builtinUid, 'owner'] ); const jwtSecret = crypto.randomBytes(32).toString('hex'); diff --git a/backend/routes/users.js b/backend/routes/users.js index 1fcce30..2ccc6b0 100644 --- a/backend/routes/users.js +++ b/backend/routes/users.js @@ -19,6 +19,7 @@ const express = require('express'); const bcrypt = require('bcryptjs'); +const crypto = require('crypto'); const { query, getRow } = require('../db'); const { authenticate, requireRole } = require('../middleware/auth'); @@ -115,10 +116,12 @@ router.post('/', authenticate, requireRole('owner','admin'), async (req, res) => if (await getRow('SELECT id FROM users WHERE username = ?', [username])) return res.status(400).json({ error: '用户名已存在' }); if (await getRow('SELECT id FROM users WHERE email = ?', [email])) return res.status(400).json({ error: '邮箱已被使用' }); const hashed = bcrypt.hashSync(password, 10); - const r = await query('INSERT INTO users(username, password, email, game_name, game_uid, role, source, active, email_verified) VALUES (?,?,?,?,?,?,?,1,1)', [username, hashed, email, game_name, game_uid||'', role, source || '']); + // 游戏UID为内置参数: 管理员未指定时自动生成 + const builtinUid = game_uid || ('U' + crypto.randomBytes(6).toString('hex').toUpperCase()); + const r = await query('INSERT INTO users(username, password, email, game_name, game_uid, role, source, active, email_verified) VALUES (?,?,?,?,?,?,?,1,1)', [username, hashed, email, game_name, builtinUid, role, source || '']); try { await query('INSERT INTO user_identities(user_id, source, game_name, game_uid) VALUES (?,?,?,?)', - [r.insertId, source || '', game_name, game_uid || '']); + [r.insertId, source || '', game_name, builtinUid]); } catch {} await query("INSERT INTO audit_logs(user_id, username, action, entity_type, entity_id, details) VALUES (?,?,?,?,?,?)", [req.user.id, req.user.username, 'create_user', 'user', r.insertId, `创建用户 ${username}`]); res.status(201).json({ id: r.insertId, message: '创建成功' }); diff --git a/public/js/pages/dashboard.js b/public/js/pages/dashboard.js index fac0aa0..f992ddc 100644 --- a/public/js/pages/dashboard.js +++ b/public/js/pages/dashboard.js @@ -68,13 +68,12 @@ const Dashboard = {
| 来源 | 游戏名 | UID | 绑定时间 | 操作 | |||||
|---|---|---|---|---|---|---|---|---|---|
| 来源 | 游戏名 | 绑定时间 | 操作 | ||
|---|---|---|---|---|---|
| ${U.esc(it.source||'-')} | -${U.esc(it.game_name)} | ${U.esc(it.game_uid||'-')} | +${U.esc(it.game_name)} | ${U.date(it.created_at)} | ${idents.length > 1 ? `` : '主身份'} |
同一账号可绑定多个来源身份,提交工单时选择使用哪个身份。
@@ -123,15 +122,6 @@ const Dashboard = { @@ -142,44 +132,13 @@ const Dashboard = { sel.innerHTML = list.length ? list.map(s => ``).join('') : ''; - toggleSource(); }).catch(()=>{}); - const toggleSource = () => { - const src = document.getElementById('ident-source').value; - const isSkin = src === 'skin'; - document.getElementById('ident-uid-group').style.display = isSkin ? 'none' : ''; - document.getElementById('ident-skin-group').classList.toggle('hidden', !isSkin); - }; - document.getElementById('ident-source').onchange = toggleSource; - // 自动带出站点配置的皮肤站地址 - API.get('/settings/skin-site').then(r => { - if (r.site && !document.getElementById('ident-site').value) document.getElementById('ident-site').value = r.site; - }).catch(()=>{}); - document.getElementById('ident-fetch-btn').onclick = async () => { - const site = document.getElementById('ident-site').value.trim(); - const name = document.getElementById('ident-name').value.trim(); - if (!site) return alert('请填写皮肤站地址'); - if (!name) return alert('请先填写游戏名(皮肤站用户名)'); - const btn = document.getElementById('ident-fetch-btn'); - btn.disabled = true; btn.innerHTML = ' 查询中'; - try { - const r = await API.get(`/settings/uuid-lookup?site=${encodeURIComponent(site)}&name=${encodeURIComponent(name)}`); - if (r.found) { - document.getElementById('ident-uid').value = r.uuid; - alert('已获取 UUID: ' + r.uuid); - } else { - alert(r.message || '未找到该用户名'); - } - } catch (ex) { alert(ex.message); } - btn.disabled = false; btn.innerHTML = ' 获取UUID'; - }; document.getElementById('ident-form').onsubmit = async e => { e.preventDefault(); try { await API.post('/auth/identities', { source: document.getElementById('ident-source').value, game_name: document.getElementById('ident-name').value, - game_uid: document.getElementById('ident-uid').value, }); App.closeModal(); this.mount(); diff --git a/public/js/pages/home.js b/public/js/pages/home.js index 5e69b69..5bdb173 100644 --- a/public/js/pages/home.js +++ b/public/js/pages/home.js @@ -65,7 +65,7 @@ const HomePage = { API.get(`/tickets/tracking?token=${token}`).then(tickets => { const t = tickets.find(x=>x.id===id); if(!t) return; - document.getElementById('tkd').innerHTML = `系统已就绪,正在刷新并跳转登录...