Add API token authentication support
This commit is contained in:
30
server.js
30
server.js
@@ -11,6 +11,7 @@ const { sendMail, fetchLatestEmails, fetchMessageDetail } = require('./mailServi
|
||||
const app = express();
|
||||
const port = Number(process.env.PORT || 3000);
|
||||
const appPassword = String(process.env.APP_PASSWORD || '').trim();
|
||||
const apiToken = String(process.env.API_TOKEN || '').trim();
|
||||
const authCookieName = 'mail_sr_auth';
|
||||
const authCookieValue = appPassword
|
||||
? crypto.createHash('sha256').update(appPassword).digest('hex')
|
||||
@@ -22,7 +23,7 @@ app.use(express.urlencoded({ extended: false }));
|
||||
app.use(express.static(path.join(__dirname, 'public')));
|
||||
|
||||
app.get('/api/auth/status', (req, res) => {
|
||||
res.json({ ok: true, authenticated: isAuthenticated(req) });
|
||||
res.json({ ok: true, authenticated: isAuthenticated(req), tokenEnabled: Boolean(apiToken) });
|
||||
});
|
||||
|
||||
app.post('/api/auth/login', (req, res) => {
|
||||
@@ -45,7 +46,7 @@ app.post('/api/auth/logout', (_req, res) => {
|
||||
});
|
||||
|
||||
app.use('/api', (req, res, next) => {
|
||||
if (!appPassword) {
|
||||
if (!appPassword && !apiToken) {
|
||||
return next();
|
||||
}
|
||||
|
||||
@@ -53,11 +54,11 @@ app.use('/api', (req, res, next) => {
|
||||
return next();
|
||||
}
|
||||
|
||||
if (!isAuthenticated(req)) {
|
||||
return res.status(401).json({ error: '请先输入访问密码' });
|
||||
if (isApiTokenAuthenticated(req) || isAuthenticated(req)) {
|
||||
return next();
|
||||
}
|
||||
|
||||
return next();
|
||||
return res.status(401).json({ error: '请先登录或提供有效的 API Token' });
|
||||
});
|
||||
|
||||
const getChannelStmt = db.prepare('SELECT * FROM channels WHERE id = ?');
|
||||
@@ -422,6 +423,25 @@ function isAuthenticated(req) {
|
||||
return cookies[authCookieName] === authCookieValue;
|
||||
}
|
||||
|
||||
function isApiTokenAuthenticated(req) {
|
||||
if (!apiToken) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const bearerToken = getBearerToken(req.headers.authorization || '');
|
||||
const headerToken = String(req.headers['x-api-token'] || '').trim();
|
||||
return bearerToken === apiToken || headerToken === apiToken;
|
||||
}
|
||||
|
||||
function getBearerToken(authorizationHeader) {
|
||||
const value = String(authorizationHeader || '').trim();
|
||||
if (!value.toLowerCase().startsWith('bearer ')) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return value.slice(7).trim();
|
||||
}
|
||||
|
||||
function parseCookies(cookieHeader) {
|
||||
return String(cookieHeader || '')
|
||||
.split(';')
|
||||
|
||||
Reference in New Issue
Block a user