众所周知,ShareToken关键就是要share,如果不share那么直接使用at不好么?
前面写了一篇安卓手机的教程,可是感觉还是比较麻烦,毕竟还要装一个APP,如果放在web端,那不是真就成了有手就行?
由于Helper还没见复活,我拿大善人的workers搞了一个获取share_token的页面,让你随时随地,轻松的得到share_token,分享给他人。
1 目前实现的功能:
1.1 自动access_token续期
每次打开网页都会自动检测at是否到期,如果发现到期了自动通过rt更新
1.2 access_token可以使用服务器保存的值,不用每次都输入,也可以手动输入
如果是分享给朋友共享你的账号,那么只需要让朋友(或者你自己)打开网页,填入unique_name,就能拿到fk了。丝滑!
如果是分享给其他人用,单纯的提供一个获取功能,不希望他用你的账号,那么修改代码第55 行即可。
1.3 一键复制share_token
1.4 一键跳转聊天页面
fk有了,可以直接跳转到demo.oaifree.com开始聊天,这里使用了fk拼到url里边的方式,点击按钮就可以直接开聊。你也可以使用自己反代了的域名,自己改相应的代码部分。
2 食用方法(借助CloudFlare):
2.1 新建一个命名空间KV,名称随便起比如oai_global_variables
2.2 给命名空间里边添加两个变量rt 和at ,值分别是你的rt和at。
2.3新建一个workers,名称随便。
2.4 编辑worker代码:把这个代码完全贴进去(原来自带的删空),点击部署
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) { // @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(); // 假设服务器返回的是 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 }); } }
// 如果 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 show_userinfo = formData.get('show_userinfo') || '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, show_userinfo }).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';
const resultHtml = ` <!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; } 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: 150px; /* Adjust height based on your needs */ } button { background-color: #007BFF; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; font-size: 16px; } button:hover { background-color: #0056b3; } @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> <br></br> <button onclick="goToOtherPage1()">去聊天(旧页面)</button> <br></br> <button onclick="goToOtherPage2()">去聊天(新页面)</button> <script> function copyTokenKey() { const copyText = document.getElementById("tokenKey"); copyText.select(); document.execCommand("copy"); alert("已复制: " + copyText.value); } function goToOtherPage1() { window.location.href = 'https://demo.oaifree.com/auth/login_share?token=${tokenKey}'; } function goToOtherPage2() { window.location.href = 'https://new.oaifree.com'; // } </script> <a href="/">返回</a> <h1>响应原文</h1> <textarea id="response" readonly>${responseText}</textarea> </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 { 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 { display: block; margin-bottom: 10px; font-size: 16px; } input[type="text"], input[type="checkbox"] { width: calc(100% - 22px); padding: 10px; margin-top: 5px; margin-bottom: 20px; border-radius: 5px; border: 1px solid #ccc; } button { background-color: #007BFF; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; font-size: 16px; } button:hover { background-color: #0056b3; } @media (max-width: 768px) { body { padding: 10px; } form { padding: 15px; } } </style> </head> <body> <h1>欢迎使用ChatGPT</h1> <form method="POST"> <label for="unique_name">Unique Name(必须输入,以区分身份、会话隔离、聊天记录保存。):</label> <input type="text" id="unique_name" name="unique_name" placeholder="只能由数字和字母构成" required value=""> <details> <summary>更多选项(不懂则无需更改)</summary> <br></br> <div> <label for="access_token">Access Token:</label> <input type="text" id="access_token" name="access_token" placeholder="your access token" value="">
<label for="site_limit">Site Limit:</label> <input type="text" id="site_limit" name="site_limit" placeholder="All" value="">
<label for="expires_in">Expires In:</label> <input type="text" id="expires_in" name="expires_in" placeholder="以秒为单位,0表示永不过期" value="0">
<label for="gpt35_limit">GPT-3.5 Limit:</label> <input type="text" id="gpt35_limit" name="gpt35_limit" placeholder="Usage counts, with negative values indicating no limitation" value="-1">
<label for="gpt4_limit">GPT-4 Limit:</label> <input type="text" id="gpt4_limit" name="gpt4_limit" placeholder="Usage counts, with negative values indicating no limitation" value="-1"> </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' }, }); } }
2.5 给workers绑定KV
在你刚创建的workers设置界面,变量-KV命名空间绑定,把刚刚建好的KV绑定上去
注意:变量名称一定要写 oai_global_variables ,然后点部署
这时候打开你workers的网页,就可以使用了!
2.6 绑定自定义域名
进阶用户自行绑定域名,这个不在这里教了,使用worker路由即可。要注意DNS里边把你用的域名解析到cf的网络中来。
- 你甚至可以用二级目录,比如你的域名是
oainotfree.com
你可以把chat.orinotfree.com/* 路由到反代始皇网站,把chat.orinotfree.com/fk 路由到这个workers,同一个域名不同二级目录便拥有了不同的功能。
3 没有rt和at?
看这里
因为我不懂js,代码是ChatGPT写的,可能比较丑陋,不过能跑就行
Enjoy~ |