Files
MC_Report/backend/middleware/auth.js
canglan 8c5ce78fd0 chore: add AGPLv3 copyright header to all source files
- 52 JS files (backend + public/js): header with
  Copyright (C) 2026 Sea Network Technology Studio
  Author: CangLan <admin@sea-studio.top>
  + AGPLv3 notice
- idempotent (skips if header present), all syntax-checked
2026-08-19 20:27:05 +08:00

62 lines
2.3 KiB
JavaScript

/*
* MC Report System
* Copyright (C) 2026 Sea Network Technology Studio
* Author: CangLan <admin@sea-studio.top>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const jwt = require('jsonwebtoken');
const { getConfig } = require('../db');
let cachedSecret = null;
function getSecret() {
if (cachedSecret) return cachedSecret;
try {
cachedSecret = getConfig()?.jwt_secret || process.env.JWT_SECRET;
} catch {}
if (!cachedSecret) throw new Error('JWT_SECRET not configured');
return cachedSecret;
}
function generateToken(user) {
return jwt.sign({ id: user.id, username: user.username, role: user.role, game_name: user.game_name, game_uid: user.game_uid, email: user.email }, getSecret(), { expiresIn: '72h' });
}
function verifyToken(token) { return jwt.verify(token, getSecret()); }
function authenticate(req, res, next) {
const h = req.headers.authorization;
if (!h || !h.startsWith('Bearer ')) return res.status(401).json({ error: '请先登录' });
try { req.user = verifyToken(h.split(' ')[1]); next(); }
catch (e) { return res.status(401).json({ error: e.name === 'TokenExpiredError' ? '登录已过期,请重新登录' : '无效的认证信息' }); }
}
function requireRole(...roles) {
return (req, res, next) => {
if (!req.user) return res.status(401).json({ error: '请先登录' });
if (!roles.includes(req.user.role)) return res.status(403).json({ error: '权限不足' });
next();
};
}
function optionalAuth(req, res, next) {
const h = req.headers.authorization;
if (h && h.startsWith('Bearer ')) { try { req.user = verifyToken(h.split(' ')[1]); } catch {} }
next();
}
module.exports = { generateToken, verifyToken, authenticate, requireRole, optionalAuth };