去年11月,我给这位大佬的fuclaude号池做了一些修改,现在我又进行了一次改进,比上次的版本更加美观,并且加上了页面样式切换按钮
演示效果如下:

在cloudflare worker中,新建项目,把下面的代码全部复制粘贴,修改key和密码之后,选择部署 即可使用
const CONFIG = {
ORIGINAL_WEBSITE: "https://demo.fuclaude.com",
SESSION_KEYS: [ "sk-ant-sid01-1", "sk-ant-sid01-2","sk-ant-sid01-3"
],
KEY_NAMES: ["1", "2", "3"],
SITE_PASSWORD: "site_passwd",
GUEST_PASSWORD: "guest_passwd"
};
export default {
async fetch(request, env, ctx) {
return await handleRequest(request);
}
};
async function handleRequest(request) {
const url = new URL(request.url);
if (url.pathname === '/login') return handleRootPath(request, url, true);
if (url.pathname === '/') return handleRootPath(request, url);
return proxyRequest(request);
}
async function handleRootPath(request, url, forceLogin = false) {
const cookie = request.headers.get('Cookie') || '';
if (!forceLogin && cookie.includes('_Secure-next-auth.session-data')) {
return Response.redirect(`${url.origin}/new`, 302);
}
if (request.method === 'POST') return handleLogin(request, url);
return new Response(formHtml, { headers: { 'Content-Type': 'text/html; charset=utf-8' } });
}
async function handleLogin(request, url) {
try {
const formData = await request.formData();
const loginType = formData.get('login_type');
const selectedKeyIndex = formData.get('session_key_index');
let body = { 'session_key': CONFIG.SESSION_KEYS[selectedKeyIndex] };
if (loginType === 'site') {
const sitePassword = formData.get('site_password');
if (sitePassword !== CONFIG.SITE_PASSWORD) {
return new Response('站点密码错误', { status: 403, headers: { 'Content-Type': 'text/plain; charset=utf-8' } });
}
} else if (loginType === 'guest') {
const username = formData.get('username');
const guestPassword = formData.get('guest_password');
if (!username || username.trim() === '') {
return new Response('访客登录必须提供用户名', { status: 400, headers: { 'Content-Type': 'text/plain; charset=utf-8' } });
}
if (guestPassword !== CONFIG.GUEST_PASSWORD) {
return new Response('访客密码错误', { status: 403, headers: { 'Content-Type': 'text/plain; charset=utf-8' } });
}
body.unique_name = username;
} else {
return new Response('无效的登录类型', { status: 400, headers: { 'Content-Type': 'text/plain; charset=utf-8' } });
}
const authUrl = `${CONFIG.ORIGINAL_WEBSITE}/manage-api/auth/oauth_token`;
const apiResponse = await fetch(authUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body)
});
if (!apiResponse.ok) throw new Error(`API request failed with status ${apiResponse.status}`);
const respJson = await apiResponse.json();
const login_url = respJson.login_url || '/';
return Response.redirect(`https://${url.host}${login_url}`, 302);
} catch (error) {
console.error('Login error:', error);
return new Response('登录过程中发生错误', { status: 500, headers: { 'Content-Type': 'text/plain; charset=utf-8' } });
}
}
async function proxyRequest(request) {
const url = new URL(request.url);
const newUrl = `${CONFIG.ORIGINAL_WEBSITE}${url.pathname}${url.search}`;
const modifiedRequest = new Request(newUrl, request);
const response = await fetch(modifiedRequest);
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('text/html') && url.pathname !== '/login_oauth') {
let html = await response.text();
const regex = /<div[^>]*>(?=[\s\S]*?<h3[\s\S]*?<\/h3>)(?=[\s\S]*?<p[\s\S]*?<\/p>)(?=[\s\S]*?<div[\s\S]*?<\/div>)[\s\S]*?<\/div>/gi;
html = html.replace(regex, '');
return new Response(html, { headers: response.headers });
}
return response;
}
const formHtml = `<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Claude镜像站</title>
<link rel="icon" href="https://www.anthropic.com/favicon.ico" type="image/x-icon">
<style>
:root {
--bg-dark: rgb(33, 33, 33);
--container-bg-dark: rgb(45, 45, 45);
--text-dark: #e0e0e0;
--bg-light: #edeadf;
--container-bg-light: #f3f1ea;
--text-light: #333333;
--button-bg: #ab5235;
--button-hover: #c25f3d;
--input-focus: #d87347;
}
/* 主题相关样式 */
[data-theme="dark"] {
--bg: var(--bg-dark);
--container-bg: var(--container-bg-dark);
--text: var(--text-dark);
}
[data-theme="light"] {
--bg: var(--bg-light);
--container-bg: var(--container-bg-light);
--text: var(--text-light);
}
body, html {
height: 100dvh;
margin: 0;
overflow: hidden;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
background: var(--bg);
color: var(--text);
line-height: 1.6;
}
.container {
display: flex;
justify-content: center;
align-items: center;
height: 100dvh;
padding: 20px;
box-sizing: border-box;
backdrop-filter: blur(10px);
background-image: linear-gradient(120deg, rgba(0,0,0,0.05) 0%, rgba(0,0,0,0.02) 100%);
}
.form-container {
padding: 30px;
border-radius: 20px;
width: 100%;
max-width: 400px;
background: var(--container-bg);
transition: all 0.3s ease;
position: relative;
backdrop-filter: blur(8px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
}
h1 {
text-align: center;
margin-bottom: 25px;
font-size: 28px;
font-weight: 700;
letter-spacing: -0.5px;
background: linear-gradient(45deg, var(--button-bg), var(--button-hover));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
padding-bottom: 5px;
}
.form-group {
margin-bottom: 20px;
position: relative;
}
label {
display: block;
margin-bottom: 8px;
font-weight: 600;
font-size: 0.95rem;
color: var(--text);
opacity: 0.85;
}
input[type="text"], input[type="password"] {
width: 100%;
padding: 12px 16px;
box-sizing: border-box;
font-size: 16px;
border-radius: 12px;
transition: all 0.3s ease;
background-color: var(--bg);
border: 1px solid rgba(0, 0, 0, 0.1);
color: var(--text);
}
input[type="text"]:focus, input[type="password"]:focus {
outline: none;
border-color: var(--input-focus);
box-shadow: 0 0 0 3px rgba(171, 82, 53, 0.15);
}
button {
width: 100%;
padding: 12px 16px;
background-color: var(--button-bg);
color: white;
border: none;
border-radius: 12px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
margin-bottom: 12px;
transition: all 0.3s ease;
box-shadow: 0 4px 12px rgba(171, 82, 53, 0.2);
}
button:hover {
background-color: var(--button-hover);
transform: translateY(-1px);
}
.key-buttons {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
margin-bottom: 12px;
}
.key-button {
flex: 1;
padding: 14px;
color: white;
background-color: var(--button-bg);
border: none;
border-radius: 12px;
cursor: pointer;
font-size: 15px;
font-weight: 600;
text-align: center;
margin-bottom: 0;
transition: all 0.3s ease;
box-shadow: 0 4px 12px rgba(171, 82, 53, 0.2);
position: relative;
overflow: hidden;
}
.key-button::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(45deg, transparent, rgba(255,255,255,0.1), transparent);
transform: translateX(-100%);
transition: 0.5s;
}
.key-button:hover::before {
transform: translateX(100%);
}
.switch-btn {
background-color: transparent;
color: var(--button-bg);
border: 2px solid var(--button-bg);
font-weight: 600;
box-shadow: none;
margin-top: 6px;
}
.switch-btn:hover {
background-color: rgba(171, 82, 53, 0.08);
}
.hidden {
display: none;
}
/* 主题切换按钮样式 */
.theme-toggle {
position: fixed;
top: 20px;
right: 20px;
width: 40px;
height: 40px;
border-radius: 50%;
background: transparent;
border: none;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
z-index: 1000;
padding: 0;
}
.theme-toggle:hover {
transform: scale(1.2);
}
/* 亮色模式下悬浮效果 */
[data-theme="light"] .theme-toggle:hover {
background: #202020;
}
.theme-toggle svg {
width: 20px;
height: 20px;
transition: all 0.3s ease;
}
/* 暗色模式下月亮图标为浅色 */
[data-theme="dark"] .theme-toggle .moon-icon {
fill: #f2efe8;
}
/* 亮色模式下太阳图标为橙色 */
[data-theme="light"] .theme-toggle .sun-icon {
fill: #c25f3d;
}
/* 亮色模式下悬浮时太阳图标放大并保持颜色 */
[data-theme="light"] .theme-toggle:hover .sun-icon {
fill: #c25f3d;
transform: scale(1.1);
}
.theme-toggle .sun-icon {
display: none;
}
.theme-toggle .moon-icon {
display: block;
}
[data-theme="light"] .theme-toggle .sun-icon {
display: block;
}
[data-theme="light"] .theme-toggle .moon-icon {
display: none;
}
@media (max-width: 480px) {
.form-container {
padding: 25px 20px;
}
h1 {
font-size: 24px;
}
.key-buttons {
gap: 12px;
}
.key-button {
padding: 12px;
font-size: 14px;
}
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.form-container {
animation: fadeIn 0.5s ease-out;
}
</style>
</head>
<body>
<button class="theme-toggle" onclick="toggleTheme()" aria-label="切换主题">
<svg class="sun-icon" viewBox="0 0 24 24">
<path d="M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zM2 13h2c.55 0 1-.45 1-1s-.45-1-1-1H2c-.55 0-1 .45-1 1s.45 1 1 1zm18 0h2c.55 0 1-.45 1-1s-.45-1-1-1h-2c-.55 0-1 .45-1 1s.45 1 1 1zM11 2v2c0 .55.45 1 1 1s1-.45 1-1V2c0-.55-.45-1-1-1s-1 .45-1 1zm0 18v2c0 .55.45 1 1 1s1-.45 1-1v-2c0-.55-.45-1-1-1s-1 .45-1 1zM5.99 4.58c-.39-.39-1.03-.39-1.41 0-.39.39-.39 1.03 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0s.39-1.03 0-1.41L5.99 4.58zm12.37 12.37c-.39-.39-1.03-.39-1.41 0-.39.39-.39 1.03 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0 .39-.39.39-1.03 0-1.41l-1.06-1.06zm1.06-10.96c.39-.39.39-1.03 0-1.41-.39-.39-1.03-.39-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0l1.06-1.06zM7.05 18.36c.39-.39.39-1.03 0-1.41-.39-.39-1.03-.39-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0l1.06-1.06z"/>
</svg>
<svg class="moon-icon" viewBox="0 0 24 24">
<path d="M12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9 9-4.03 9-9c0-.46-.04-.92-.1-1.36-.98 1.37-2.58 2.26-4.4 2.26-3.03 0-5.5-2.47-5.5-5.5 0-1.82.89-3.42 2.26-4.4-.44-.06-.9-.1-1.36-.1z"/>
</svg>
</button>
<div class="container">
<div class="form-container" id="keySelection">
<h1>Claude镜像站</h1>
<div class="key-buttons" id="keyButtons"></div>
</div>
<div class="form-container hidden" id="guestLogin">
<h1>访客登录</h1>
<form method="POST">
<input type="hidden" name="login_type" value="guest">
<input type="hidden" id="guest_selected_key_index" name="session_key_index" value="">
<div class="form-group">
<label for="username">用户名:</label>
<input type="text" id="username" name="username" placeholder="用于隔离会话,填一个别人猜不到的即可" required>
</div>
<div class="form-group">
<label for="guest_password">访客密码:</label>
<input type="password" id="guest_password" name="guest_password" placeholder="输入访客密码" required>
</div>
<button type="submit">登录</button>
</form>
<button class="switch-btn" onclick="toggleForm()">切换到站点密码登录</button>
<button class="switch-btn" onclick="backToKeySelection()">返回选择通道</button>
</div>
<div class="form-container hidden" id="siteLogin">
<h1>站点密码登录</h1>
<form method="POST">
<input type="hidden" name="login_type" value="site">
<input type="hidden" id="site_selected_key_index" name="session_key_index" value="">
<div class="form-group">
<label for="site_password">站点密码:</label>
<input type="password" id="site_password" name="site_password" placeholder="输入站点密码" required>
</div>
<button type="submit">登录</button>
</form>
<button class="switch-btn" onclick="toggleForm()">切换到访客登录</button>
<button class="switch-btn" onclick="backToKeySelection()">返回选择通道</button>
</div>
</div>
<script>
const keyCount = ${CONFIG.SESSION_KEYS.length};
const keyNames = ${JSON.stringify(CONFIG.KEY_NAMES)};
function createKeyButtons() {
const container = document.getElementById('keyButtons');
for (let i = 0; i < keyCount; i++) {
const button = document.createElement('button');
button.type = 'button';
button.className = 'key-button';
button.textContent = keyNames[i] || \`通道 \${i + 1}\`;
button.onclick = () => selectKey(i);
container.appendChild(button);
}
}
function selectKey(index) {
document.getElementById('guest_selected_key_index').value = index;
document.getElementById('site_selected_key_index').value = index;
document.getElementById('keySelection').classList.add('hidden');
document.getElementById('guestLogin').classList.remove('hidden');
}
function backToKeySelection() {
document.getElementById('keySelection').classList.remove('hidden');
document.getElementById('guestLogin').classList.add('hidden');
document.getElementById('siteLogin').classList.add('hidden');
}
function toggleForm() {
const guestLogin = document.getElementById('guestLogin');
const siteLogin = document.getElementById('siteLogin');
if (guestLogin.classList.contains('hidden')) {
guestLogin.classList.remove('hidden');
siteLogin.classList.add('hidden');
} else {
guestLogin.classList.add('hidden');
siteLogin.classList.remove('hidden');
}
}
createKeyButtons();
function toggleTheme() {
const html = document.documentElement;
const currentTheme = html.getAttribute('data-theme') || 'light';
const newTheme = currentTheme === 'light' ? 'dark' : 'light';
html.setAttribute('data-theme', newTheme);
localStorage.setItem('theme', newTheme);
}
function initTheme() {
const savedTheme = localStorage.getItem('theme');
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
const theme = savedTheme || (prefersDark ? 'dark' : 'light');
document.documentElement.setAttribute('data-theme', theme);
}
document.addEventListener('DOMContentLoaded', initTheme);
</script>
</body>
</html>`;


