mirror of
https://github.com/ZSCGR/CloudFlare-ImgBed.git
synced 2026-08-20 15:43:42 +08:00
- Add passwordHash.js: SHA-256 + salt hashing with plaintext backward compatibility - Add sessionManager.js: HttpOnly cookie sessions with separate admin_session/user_session - Add sessionCheck.js: session validation endpoint for frontend route guards - Add logout.js: session destruction endpoint with authType support - Update login.js: return user_session cookie on successful login - Update check.js: return admin_session cookie on successful admin auth - Update _middleware.js: check admin_session before Basic Auth, remove WWW-Authenticate header - Update security.js: hash passwords on save, mask in GET, clear sessions on password change - Update dualAuth.js/userAuth.js: use verifyPassword and session validation
100 lines
3.3 KiB
JavaScript
100 lines
3.3 KiB
JavaScript
import { fetchSecurityConfig } from './sysConfig';
|
||
import { validateApiToken } from './tokenValidator';
|
||
import { getDatabase } from './databaseAdapter.js';
|
||
import { verifyPassword } from './passwordHash.js';
|
||
import { validateSession } from './sessionManager.js';
|
||
|
||
/**
|
||
* 客户端用户认证
|
||
* @param {Object} env - 环境变量
|
||
* @param {URL} url - 请求的URL
|
||
* @param {Request} request - 请求对象
|
||
* @param {string|null} requiredPermission - 如果提供,则进行Token验证
|
||
* @return {Promise<boolean>} 返回是否认证通过
|
||
*/
|
||
export async function userAuthCheck(env, url, request, requiredPermission = null) {
|
||
// 首先检查会话 Cookie(user 或 admin 都可以通过用户端认证)
|
||
const userSession = await validateSession(env, request, 'user');
|
||
if (userSession.valid) {
|
||
return true;
|
||
}
|
||
const adminSession = await validateSession(env, request, 'admin');
|
||
if (adminSession.valid) {
|
||
return true;
|
||
}
|
||
|
||
// 然后使用Token验证
|
||
const tokenValidation = await validateApiToken(request, getDatabase(env), requiredPermission);
|
||
if (tokenValidation.valid) {
|
||
return true;
|
||
}
|
||
|
||
// Token验证失败,继续尝试传统认证方式
|
||
const securityConfig = await fetchSecurityConfig(env);
|
||
const rightAuthCode = securityConfig.auth.user.authCode;
|
||
|
||
// 优先从请求 URL 参数获取 authCode
|
||
let authCode = url.searchParams.get('authCode');
|
||
|
||
// 如果 URL 参数中没有 authCode,从 Referer 中获取
|
||
if (!authCode) {
|
||
const referer = request.headers.get('Referer');
|
||
if (referer) {
|
||
try {
|
||
const refererUrl = new URL(referer);
|
||
authCode = new URLSearchParams(refererUrl.search).get('authCode');
|
||
} catch (e) {
|
||
console.error('Invalid referer URL:', e);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 如果 Referer 中没有 authCode,从请求头中获取
|
||
if (!authCode) {
|
||
authCode = request.headers.get('authCode');
|
||
}
|
||
|
||
// 如果请求头中没有 authCode,从 Cookie 中获取
|
||
if (!authCode) {
|
||
const cookies = request.headers.get('Cookie');
|
||
if (cookies) {
|
||
authCode = getCookieValue(cookies, 'authCode');
|
||
}
|
||
}
|
||
|
||
if (isAuthCodeDefined(rightAuthCode) && !(await isValidAuthCode(rightAuthCode, authCode))) {
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
export function UnauthorizedResponse(reason) {
|
||
return new Response(reason, {
|
||
status: 401,
|
||
statusText: "Unauthorized",
|
||
headers: {
|
||
'Access-Control-Allow-Origin': '*',
|
||
'Access-Control-Allow-Methods': 'POST, GET',
|
||
'Access-Control-Allow-Headers': 'Content-Type, Authorization, authCode',
|
||
"Content-Type": "text/plain;charset=UTF-8",
|
||
"Cache-Control": "no-store",
|
||
"Content-Length": reason.length,
|
||
},
|
||
});
|
||
}
|
||
|
||
async function isValidAuthCode(rightAuthCode, authCode) {
|
||
if (!authCode) return false;
|
||
return await verifyPassword(authCode, rightAuthCode);
|
||
}
|
||
|
||
function isAuthCodeDefined(authCode) {
|
||
return authCode !== undefined && authCode !== null && authCode.trim() !== '';
|
||
}
|
||
|
||
|
||
function getCookieValue(cookies, name) {
|
||
const match = cookies.match(new RegExp('(^| )' + name + '=([^;]+)'));
|
||
return match ? decodeURIComponent(match[2]) : null;
|
||
} |