[已经解决,就是我想到的过期的at的值问题]关于在CF上部署共享gpt镜像站遇到的问题

如图所示,今天我的team号噶了一个,然后,我手动更换了一个rt,和at的代码,也重新部署了workers,但是,我很好奇,一直用的是我失效的,at来访问gpt的网站。如图



这里面我已经切换了,at和rt,包括重新部署了一边workers。代码如下,请各位佬朋友可以一起观摩。

addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})
function parseJwt(token) {
  const base64Url = token.split('.')[1]; // 获取载荷部分
  const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/'); // 将 Base64Url 转为 Base64
  const jsonPayload = decodeURIComponent(atob(base64).split('').map(function(c) {
    return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
  }).join(''));

  return JSON.parse(jsonPayload); // 返回载荷解析后的 JSON 对象
}

function isTokenExpired(token) {
  const payload = parseJwt(token);
  const currentTime = Math.floor(Date.now() / 1000); // 获取当前时间戳(秒)
  return payload.exp < currentTime; // 检查 token 是否过期
}

async function handleRequest(request) {
  const requestURL = new URL(request.url);
  
  // ------------ 反代到 new.oaifree.com
  const path = requestURL.pathname;
  if (path !== '/auth/login_auth0' && path !== '/auth/login') {
    requestURL.host = 'new.oaifree.com';
    return fetch(new Request(requestURL, request))
  }

  // ------------ 进行拿share_token去登录
  // @ts-ignore
  const token = await oaipro_global_variables.get('at'); // 这里填入你的 JWT
  if (isTokenExpired(token)) {
    // 如果 Token 过期,执行获取新 Token 的逻辑
    const url = 'https://token.oaifree.com/api/auth/refresh';
    // @ts-ignore
    const refreshToken = await oaipro_global_variables.get('rt');  // 实际情况下你可能会从某处获取这个值
  
    // 发送 POST 请求
    const response = await fetch(url, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
        },
        body: `refresh_token=${refreshToken}`
    });
  
    // 检查响应状态
    if (response.ok) {
        const data = await response.json();
        const token = data.access_token;

        // @ts-ignore
        await oaipro_global_variables.put('at', token);
    } else {
        return new Response('Error fetching access token', { status: response.status });
    }
  }

  // 如果 Token 未过期,继续执行原来的逻辑
  if (request.method === "POST") {
    const formData = await request.formData();

    // @ts-ignore
    //const SITE_PASSWORD = await oaipro_global_variables.get('SITE_PASSWORD') || '';
    //const site_password = formData.get('site_password') || '';
    //if (site_password !== SITE_PASSWORD) {
      //return new Response('站密码错误', { status: 401 }); //如果你不需要密码访问,注释此行代码
    //}

    // @ts-ignore
    const access_token = await oaipro_global_variables.get('at')
    const unique_name = formData.get('unique_name');
     // 这里开始是新增的用户列表检查逻辑
    // @ts-ignore
    const usersListString = await oaipro_global_variables.get('users'); // 从 KV 中获取用户列表
    const usersList = usersListString ? usersListString.split(',') : []; // 将字符串转换为数组 ["xdh001", "xdh002", "xdh003"]
    if (!usersList.includes(unique_name)) {
      // 如果用户不在列表中,返回错误响应
      return new Response('No such user', { status: 403 });
    }
    const site_limit = '';
    const expires_in = '0';
    const gpt35_limit = '-1';
    const gpt4_limit = '-1';
    const show_conversations = 'false';
    const reset_limit = 'false';

    const url = 'https://chat.oaifree.com/token/register';
    const body = new URLSearchParams({
      unique_name,
      access_token, // 使用来自表单或KV变量的 access_token
      site_limit,
      expires_in,
      gpt35_limit,
      gpt4_limit,
      show_conversations,
      reset_limit
    }).toString();

    const apiResponse = await fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      },
      body: body
    });

    const respJson = await apiResponse.json();
    const tokenKey = 'token_key' in respJson ? respJson.token_key : '未找到 Share_token';

    // @ts-ignore
    const YOUR_DOMAIN = await oaipro_global_variables.get('YOUR_DOMAIN') || requestURL.host;

    return Response.redirect(`https://${YOUR_DOMAIN}/auth/login_share?token=${tokenKey}`, 301)
  } else {
    const formHtml = `
        <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
      body {
        font-family: Arial, sans-serif;
        background-color: #f4f4f4;
        padding: 20px;
      }
      form, .response-container {
        background: white;
        padding: 20px;
        border-radius: 8px;
        box-shadow: 0 2px 5px rgba(0,0,0,0.1);
        max-width: 600px;
        margin: 20px auto;
      }
      h1 {
        text-align: center; 
      }
      h2 {
        text-align: center; 
      }
      p {
        display: block;
        margin-bottom: 10px;
        font-size: 16px;
      }
      input[type="text"], textarea {
        width: calc(100% - 22px);
        padding: 10px;
        margin-top: 5px;
        margin-bottom: 20px;
        border-radius: 5px;
        border: 1px solid #ccc;
      }
      textarea {
        font-family: 'Courier New', monospace;
        background-color: #f8f8f8;
        height: 150px; /* Adjust height based on your needs */
      }
      button {
        background-color: #000000;
        color: white;
        padding: 10px 20px;
        border: none;
        border-radius: 5px;
        cursor: pointer;
        font-size: 16px;
        font-weight:600;
        width:100% !important
      }
      button:hover {
        background-color: #1e293b;
      }
      @media (max-width: 768px) {
        body, form, .response-container {
          padding: 10px;
        }
      }
      .checkbox-group {
        display: flex;
        justify-content: space-between;
      }
      .checkbox-group input[type="checkbox"] {
        margin-right: 5px;
      }
      .checkbox-group label {
        margin-right: 10px;
      }
    </style>
    </head>
    <body>
    <h1>欢迎使用ChatGPT</h1>
    <form method="POST">
      <label for="unique_name">请输入独一无二的名字,以你的区分身份,用于会话隔离:</label>
      <input type="text" id="unique_name" name="unique_name" placeholder="" required value="">
    <br></br>
      <button type="submit">访问使用</button>
    </form>
    </body>
    </html>
    `;

    return new Response(formHtml, {
      headers: {
        'Content-Type': 'text/html; charset=utf-8'
      },
    });
  }
}

我现在怀疑是这块的代码有问题,导致一直获取的之前的token如下:

function isTokenExpired(token) {
const payload = parseJwt(token);
const currentTime = Math.floor(Date.now() / 1000); // 获取当前时间戳(秒)
return payload.exp < currentTime; // 检查 token 是否过期
}预先格式化的文本

3 个赞

我打开就显示我之前的,邮箱,如图:

2 个赞

解决办法如下:就是将过期的时间注销,然后,硬生生的把at搞进去,这样连失效时间都没有了,然后你将我上面的代码直接放进去即可。
代码如下:

addEventListener('fetch', event => {
    event.respondWith(handleRequest(event.request))
})


function parseJwt(token) {
    const base64Url = token.split('.')[1]; // 获取载荷部分
    const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/'); // 将 Base64Url 转为 Base64
    const jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) {
        return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
    }).join(''));
    return JSON.parse(jsonPayload); // 返回载荷解析后的 JSON 对象
}

/*
function isTokenExpired(token) {
    const payload = parseJwt(token);
    const currentTime = Math.floor(Date.now() / 1000); // 获取当前时间戳(秒)
    return payload.exp < currentTime; // 检查 token 是否过期
}
*/

async function getOAuthLink(shareToken, proxiedDomain) {
    const url = `https://${proxiedDomain}/api/auth/oauth_token`;
    const response = await fetch(url, {
        method: 'POST',
        headers: {
            'Origin': `https://${proxiedDomain}`,
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({
            share_token: shareToken
        })
    })
    const data = await response.json();
    
    return data.login_url;
}




async function getShareToken(userName, at) {
    const url = 'https://chat.oaifree.com/token/register';
    const body = new URLSearchParams({
        // 此处为获取Share Token时的请求参数,可自行配置
        access_token: at,
        unique_name: userName,
        site_limit: '', // 限制的网站
        expires_in: '0', // token有效期(单位为秒),填 0 则永久有效
        gpt35_limit: '-1', // gpt3.5 对话限制
        gpt4_limit: '-1', // gpt4 对话限制
        show_conversations: 'false', // 是否显示所有人的会话
        show_userinfo: 'false', // 是否显示用户信息
        reset_limit: 'false' // 是否重置对话限制
    }).toString();
    const apiResponse = await fetch(url, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded'
        },
        body: body
    });
    const responseText = await apiResponse.text();
    const tokenKeyMatch = /"token_key":"([^"]+)"/.exec(responseText);
    const tokenKey = tokenKeyMatch ? tokenKeyMatch[1] : 'share token 获取失败';
    return tokenKey;
}

async function handleRequest(request) {
    const url = new URL(request.url);
    const params = new URLSearchParams(url.search);
    const userName = params.get('un');
    const at = '';

    if (!userName) {
        // 如果没有 'un' 参数,返回 HTML 表单
        return new Response(formHtml, {
            headers: {
                'Content-Type': 'text/html; charset=utf-8'
            }
        });
    }


    // @ts-ignore
    // 验证用户名是否存在
    const users = await oai_global_variables.get("users");
    if (!users.split(",").includes(userName)) {
        return new Response('用户不存在', { status: 404 });
    }

    /*
    // @ts-ignore
    const accessToken = await oai_global_variables.get('at');
    if (isTokenExpired(accessToken)) {
        // 给没有refresh token的萌新用(比如我),取消下面这行注释即可享用
        // return new Response('当前access token未更新,请联系管理员更新', { status: 401 });

        // 如果 Token 过期,执行获取新 Token 的逻辑
        const url = 'https://token.oaifree.com/api/auth/refresh';
        // @ts-ignore
        const refreshToken = await oai_global_variables.get('rt');  // 实际情况下你可能会从某处获取这个值

        // 发送 POST 请求
        const response = await fetch(url, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
            },
            body: `refresh_token=${refreshToken}`
        });

        // 检查响应状态
        if (response.ok) {
            const data = await response.json();  // 假设服务器返回的是 JSON 格式数据
            const token = data.access_token; // 直接从 JSON 中获取 access_token

            // @ts-ignore
            await oai_global_variables.put('at', token);
        } else {
            return new Response('Error fetching access token', { status: response.status });
        }
    }
    // @ts-ignore
    //const tokenPrefix = await oai_global_variables.get('token_prefix');
*/
    const shareToken = await getShareToken(userName, at);
    if (shareToken === 'share token 获取失败') {
        return new Response('token获取失败,请刷新重试', { status: 500 });
    }

    // @ts-ignore
    const proxiedDomain = await oai_global_variables.get('proxied_domain');
    return Response.redirect(await getOAuthLink(shareToken, proxiedDomain), 302);
}
// HTML 表单代码
const formHtml = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
padding: 20px;
}
form, .response-container {
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
max-width: 600px;
margin: 20px auto;
}
h1 {
text-align: center; 
}
h2 {
text-align: center; 
}
p {
display: block;
margin-bottom: 10px;
font-size: 16px;
}
input[type="text"], textarea {
width: calc(100% - 22px);
padding: 10px;
margin-top: 5px;
margin-bottom: 20px;
border-radius: 5px;
border: 1px solid #ccc;
}
textarea {
font-family: 'Courier New', monospace;
background-color: #f8f8f8;
height: 150px; /* Adjust height based on your needs */
}
button {
background-color: #000000;
color: white;
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
font-weight:600;
width:100% !important
}
button:hover {
background-color: #1e293b;
}
@media (max-width: 768px) {
body, form, .response-container {
  padding: 10px;
}
}
.checkbox-group {
display: flex;
justify-content: space-between;
}
.checkbox-group input[type="checkbox"] {
margin-right: 5px;
}
.checkbox-group label {
margin-right: 10px;
}
</style>
</head>
<body>
<h1>欢迎使用XDH的_ChatGPT</h1>
<form method="GET">
<label for="unique_name">请输入独一无二的名字,以你的区分身份,用于会话隔离:</label>
<input type="text" id="un" name="un" placeholder="" required value="">
<br></br>
<button type="submit">访问使用</button>
</form>
</body>
</html>
`;