【接力,小白向教程】兄弟们,Share token使用更更更更优雅了!重大更新!!

首先感谢这三位大佬的前期工作:

另外还有 Maple搞的去掉了交互链接直达,限制用户名白名单的版本,有需要可以去看看:

重大更新,new站支持/auth/login_share?token= 了。 原setcookie方式失效需要更新新代码。
重大更新,始皇给出了新的反代代码,以及登录方法,本贴已跟进更新。

本贴对workers代码进行了如下优化

  • 更多选项支持了 三个 两个check框选项【会话无需隔离、展示账号邮箱 重置已用次数】
    更新原因是 “久负盛名”的Share Token回来了 - #298,来自 neo
  • 微调了样式,使其略微美观
  • 将form中提示词改为了中文
  • 可选的访问权限(如不需要可注释掉27行)
    ps.如果开启你需要在生成的地址后拼接?password=你设置的密码,来登录,否则会显示为Unauthorized access.
  • 支持一键跳转到以share token登录后的地址【采用了new站方案】
    *将 马克思大佬增加的环境变量移动到KV中

部署方式奥特曼大佬的原帖 兄弟们,Share token使用更优雅了! 中图文并茂,讲的很清楚了。

需要在原帖基础上KV中增加两个参数:

PASSWORD: 设置你的密码
YOUR_DOMAIN: 直接填写new.oaifree.com或者你反代的new站

这个YOUR_DOMAIN填什么:

反代一个new站,同时增加传参setcookie的能力。
得到的地址就是your_domain
你可以直接使用始皇的 new.oaifree.com,如果你有自定义域名的需求则另外新建一个worker,反代代码如下:

export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    url.host = 'new.oaifree.com';
    return fetch(new Request(url, request))
  }
}

使用上面新的代码反代new站。更新了setcookie的方式 兼容 new.oaifree.com/auth/login_share?token= 形式


替换下面的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 url = new URL(request.url);
  const params = new URLSearchParams(url.search);
  const password = params.get('password');
  // @ts-ignore
  const PASSWORD = await oai_global_variables.get('PASSWORD');

  if (password !== PASSWORD) {
    return new Response('Unauthorized access', { status: 401 }); //如果你不需要密码访问,注释此行代码
  }

  // @ts-ignore
  const token = await oai_global_variables.get('at'); // 这里填入你的 JWT

  if (isTokenExpired(token)) {
    // 如果 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();
        const token = data.access_token;

        // @ts-ignore
        await oai_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 at = await oai_global_variables.get('at')
    const access_token = formData.get('access_token') || at; //删除行尾at变量以停止使用内置的access_token(两个竖线也需要删除)
    const unique_name = formData.get('unique_name');
    const site_limit = formData.get('site_limit') || '';
    const expires_in = formData.get('expires_in') || '';
    const gpt35_limit = formData.get('gpt35_limit') || '';
    const gpt4_limit = formData.get('gpt4_limit') || '';
    const show_conversations = formData.get('show_conversations') || 'false';
    const reset_limit = formData.get('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 responseText = await apiResponse.text();
    const tokenKeyMatch = /"token_key":"([^"]+)"/.exec(responseText);
    const tokenKey = tokenKeyMatch ? tokenKeyMatch[1] : '未找到 Share_token';
    // @ts-ignore
    const YOUR_DOMAIN = await oai_global_variables.get('YOUR_DOMAIN');
    // @ts-ignore
    const PASSWORD = await oai_global_variables.get('PASSWORD');

    const resultHtml = `
    <!DOCTYPE html>
    <html lang="zh-CN">
    <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;
      }
      label, h1, p {
        display: block;
        margin-bottom: 10px;
        font-size: 16px;
      }
      input[type="text"], input[type="checkbox"], 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: 20px;
      }
      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;
        margin-bottom: 10px;
      }
      button a{
        background-color: #000000;
        color: white;
        padding: 10px 20px;
        border: none;
        border-radius: 5px;
        cursor: pointer;
        font-size: 16px;
        font-weight:600;
        width:100% !important;
        margin-bottom: 10px;
      }
      button:hover {
        background-color: #1e293b;
      }
      button a {
        color: inherit;
        text-decoration: none;
        background: none;
        padding: 0;
        display: inline;
    }    
      @media (max-width: 768px) {
        body, form, .response-container {
          padding: 10px;
        }
      }
    </style>
    </head>
    <body>
    <div class="response-container">
      <h1>Share Token</h1>
      <textarea id="tokenKey" readonly>${tokenKey}</textarea>
      <button onclick="copyTokenKey()">一键复制</button>
      <button onclick="goToOtherPage2() " style="color: #fff227;">享用纯粹ChatGPT Plus</button>
      <script>
        function copyTokenKey() {
          const copyText = document.getElementById("tokenKey");
          copyText.select();
          document.execCommand("copy");
          alert("已复制: " + copyText.value);
        }
        function goToOtherPage2() {
          window.location.href = 'https://${YOUR_DOMAIN}/auth/login_share?token=${tokenKey}';
        }
      </script>
      <a href="/?password=${PASSWORD}>返回</a>
    </div>
    </body>
    </html>
    `;

    return new Response(resultHtml, {
      headers: {
        'Content-Type': 'text/html; charset=utf-8'
      },
    });
  } 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; 
      }
      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="">
      <details>
        <summary>更多选项(不懂则无需更改)</summary>
        <br></br>
        <div class="form-container">
            <label for="access_token">Access Token:<a target="_blank" href="https://token.oaifree.com/auth">获取?</a></label>
            <input type="text" id="access_token" name="access_token" placeholder="你的 access token" value="">

            <label for="site_limit">限制使用网站:</label>
            <input type="text" id="site_limit" name="site_limit" placeholder="可选,空则不限" value="">

            <label for="expires_in">过期秒数:</label>
            <input type="text" id="expires_in" name="expires_in" placeholder="为0取Access Token过期时间,负数吊销分享令牌" value="0">

            <label for="gpt35_limit">GPT-3.5次数:</label>
            <input type="text" id="gpt35_limit" name="gpt35_limit" placeholder="为0无法使用,负数不限制" value="-1">

            <label for="gpt4_limit">GPT-4次数:</label>
            <input type="text" id="gpt4_limit" name="gpt4_limit" placeholder="为0无法使用,负数不限制" value="-1">

            <div class="checkbox-group">
              <div>
                <input type="checkbox" id="show_conversations" name="show_conversations" value="true">
                <label for="show_conversations">会话无需隔离</label>
              </div>
<!--
              <div>
                <input type="checkbox" id="show_userinfo" name="show_userinfo" value="true">
                <label for="show_userinfo">展示账号信息</label>
              </div>
-->
              <div>
                <input type="checkbox" id="reset_limit" name="reset_limit" value="true">
                <label for="reset_limit">重置已用次数</label>
              </div>
            </div>
        </div>
    </details>
    <br></br>
      <button type="submit">获取你的访问门票 share token</button>
    </form>
    </body>
    </html>
    
    `;

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

绑定自定义域名

如果你希望使用自己的域名,请点我

ps.你也可以使用分配路由的方式来实现自定义域名访问,
请注意:你需要提前把要使用的域名通过cloudflare做DNS解析,且一定要使用cloudflare代理(即小黄云亮起)然后就可以在worker中使用URL路由


这样做的好处是你甚至可以用二级目录,比如你的域名是 oainotfree.com
你可以把chat.orinotfree.com/*路由到

反代始皇new站的worker

,把chat.orinotfree.com/fk路由到这个workers,同一个域名不同二级目录便拥有了不同的功能。

没有rt和at?

看这里

ps. 有佬友想看效果,录了个视频:
https://mp4.ziyuan.wang/view.php/6dde1686ef7ae3b8befcb99f63185904.mp4

59 个赞

感谢,放vps上试试。

2 个赞

这是cf worker,还能放vps?

3 个赞

感谢分享

2 个赞

前排一下

1 个赞

你们都好优雅啊

软件分享软件开发

成品就不放了,放了个录屏

1 个赞

牛得很啊

稍微改改改成node代码就可以了,不过没必要,白嫖不香吗?

1 个赞

真牛啊

为什么复制了你的代码放进去,打开网站是 Unauthorized access

因为默认开起来密码认证,你如果不需要注释掉第27行
需要的话再后面拼接?password=你设置的密码

请问大佬,我需要密码访问,应该怎么使用呢?比如我设置了password是123456,是网址后面拼接?password=123456 么?

1 个赞

正确的

我把your domain配置成new.oaifree.com后显示的404,是没有这个接口吗?

好好好,我感觉到了,一切都回来了,

一切都回来啦!

是的,你需要使用cf worker 反代 new.oaifree.com,并增加此setcookie接口

原内容,现已不需要

以下代码由 卡尔 · 马克思 提供
由于始皇new站代码更新,后来者以主楼为准,下面代码更新于2024-4-17 15:30,需要配合主楼代码使用

const hostname = "https://new.oaifree.com";

async function getCookies(shareToken) {
    try {
        const response = await fetch(`${hostname}/auth/login_token`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
            body: 'action=token&access_token=' + encodeURIComponent(shareToken),
        });
        if (!response.ok) {
            throw new Error(`HTTP status ${response.status}`);
        }
        const cookies = response.headers.get('Set-Cookie');
        if (!cookies) {
            throw new Error('No cookies set by the response');
        }
        return cookies;
    } catch (error) {
        console.error('Error fetching cookies:', error);
        return null; // Return null if there's an error
    }
}

async function handleRequest(request) {
    let url = new URL(request.url);
    if (url.pathname === '/auth/login_share') {
        const accessToken = url.searchParams.get('token');
        if (!accessToken) {
            return new Response('Access token is required', { status: 400 });
        }

        const cookies = await getCookies(accessToken);
        if (!cookies) {
            return new Response('Failed to retrieve cookies', { status: 500 });
        }

        const response = Response.redirect(url.origin, 302);
        const newHeaders = new Headers(response.headers);
        newHeaders.append("Set-Cookie", cookies);
        return new Response(response.body, {
            status: response.status,
            statusText: response.statusText,
            headers: newHeaders
        });
    }
    return fetch(new Request(hostname + url.pathname, request));
}

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

3 个赞

先马克