chat2api 优雅接力,自动刷新accesstoken

本文基于

实现了使用 refreshToken 自动刷新 accessToken 一劳永逸地来使用 api.oaifree.com 的 chat2api接口。

在复用之前文章中的kv变量”at”和“rt”的基础上,新增 “auth_key” 用来作为 api_key 的验证。
用通俗的话来说就是,在使用 chat2api 接口的时候,api_key不必设置为 accessToken, 而是设置为你在kv里面自定义 “auth_key” 的值即可。 CF worker 验证了key符合之后,会用kv中存储的”at”去最终调用chat2api接口, “at”过期的话也会实时用 ”rt” 去刷新 “at”.

worker代码:
20240502 删除了重复代码,并修改了一处bug

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) {
  // 1. 目标反代 URL
  const url = new URL(request.url);
  url.host = 'api.oaifree.com';

// 2. 获取 Authorization header
  const authHeader = request.headers.get('Authorization');
  const apikey = authHeader ? authHeader.split(' ')[1] : null;

// 3. 检查 token
  const auth_key = await oai_global_variables.get('auth_key')

  if (!apikey || apikey !== auth_key) {
  // 4. Token 验证失败
    return new Response('Unauthorized', { status: 401 });
  }

  // ------------ get at
  let 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();
          token = data.access_token;
          // @ts-ignore
          await oai_global_variables.put('at', token);
      } else {
          return response
      }
  }
  // 如果 Token 未过期,继续执行原来的逻
  // 5. 替换 token 并转发请求
const modifiedHeaders = new Headers(request.headers);
modifiedHeaders.set('Authorization', 'Bearer '+token);

// 创建新的请求对象以转发
const newRequest = new Request(url, {
  method: request.method,
  headers: modifiedHeaders,
  body: request.body
});

// 发送新的请求到目标 API
const response = await fetch(newRequest);
return response;
} 
62 个赞

这种有引文的帖子,非常感谢,我很喜欢!

8 个赞

多谢分享,支持一波

7 个赞

感谢分享,收藏了

7 个赞

干货,已赞,收藏

7 个赞

感谢

7 个赞

感谢大佬分享

7 个赞

Uncaught SyntaxError: Unexpected end of input at worker.js:253:41 (Code: 10021)

7 个赞

有使用案例吗

7 个赞

虽然看不懂但是很牛逼

4 个赞

麻烦在worker调试里看看哪一行?

2 个赞

就是始皇的chat2api的接口,需要plus

3 个赞

6 的大佬,收藏了,起床试试

4 个赞

哦吼.留下来

2 个赞

就是最后一行,我是直接把代码替换之前的worker就行吗?

Uncaught SyntaxError: Unexpected end of input at worker.js:253:41 (Code: 10021)

哦哦少个}

1 个赞

啊,真服了(;一_一),买不起plus啊,路过

1 个赞

最后少了个},补上了

1 个赞

成功了吗

1 个赞