##2025/3/24 15:16:34:
cloudflare-memoflow 添加 github app auth 登录
github commit:
add github app auth
https://github.com/qyzhizi/hono-auth-test-app-D1-func/commit/18c2c22cc144463f3c8cae04569a92d1b88f732f
update GitHub 授权回调路由
https://github.com/qyzhizi/hono-auth-test-app-D1-func/commit/271a4a47c5078c75b3de9213637887821ca0bd0d
这两个提交,实现了 浏览器中输入 https://github.com/login/oauth/authorize?client_id=Iv23lifuoku8yVW9MtLh
就可以返回 accesstoken 的信息,其中 client_id=Iv23lifuoku8yVW9MtLh
是 github app 的信息,这样其实是写死了,应该从环境变量中获取 这个client_id 信息,然后再动态发送这个GET请求。
这里是参考了 Memoflow 的相关函数,让 AI 以 cloudflare hono 的方式重构 ,没有使用第三方库,而是直接发送 url 请求,相对来说更简单方便。
add button login with github
https://github.com/qyzhizi/hono-auth-test-app-D1-func/commit/cab6225bc674020029960f56ff5ff53900df3c59
add github auth redirect
https://github.com/qyzhizi/hono-auth-test-app-D1-func/commit/16a78478ee8294e9c4a5a9721a1af0b60302dc20
这两个提交是添加了一个按钮,可以进行 github app auth 认证。实现了上面的要求,即从环境变量中获取 这个client_id 信息,然后再动态发送这个GET请求
类型定义文件
另外填加了 env.d.ts 这个文件,这个文件是一个类型定义文件,可以这样使用:
// 定义处理函数
export const githubAuthHandler = (c: Context<{ Bindings: CloudflareEnv }>) => {
// 从环境变量中获取 GitHub Client ID
const clientId = c.env.GITHUB_APP_CLIENT_ID
const githubAuthUrl = `https://github.com/login/oauth/authorize?client_id=${clientId}`
return c.redirect(githubAuthUrl)
}
其中 CloudflareEnv
是 env.d.ts 这个文件 定义的类型:
// Generated by Wrangler by running `wrangler types --env-interface CloudflareEnv env.d.ts`
interface CloudflareEnv {
GITHUB_APP_CLIENT_ID: "Iv23lifuoku8yVW9MtLh";
GITHUB_APP_CLIENT_SECRETS: "2a4e48523ee020f1d1a47ae13fca31f72cdd4800";
ACCESS_TOKEN_SECRET: string;
REFRESH_TOKEN_SECRET: string;
ACCESS_TOKEN_EXPIRY: string;
REFRESH_TOKEN_EXPIRY: string;
GITHUB_ID: string;
GITHUB_SECRET: string;
DB: D1Database;
}
GitHub app 注册
填写的 callback
https://hono-auth-test-app-d1-func.pages.dev/api/github-app-auth-callbackuu
Repository permissions 3 selected
- Codespaces
- Commit statuses
- Contents
Account permissions 1 selected
- Email addresses read only
AI 协助 函数的重构与解耦
first example:
def get_access_token(self, code):
CLIENT_SECRET = CONF.diary_log['CLIENT_SECRET']
CLIENT_ID = CONF.diary_log['CLIENT_ID']
# 回调 URL,需与 GitHub App 中设置的一致
# REDIRECT_URI = '/v1/diary-log/github-authenticate-callback'
# 使用 code 获取访问令牌
token_url = 'https://github.com/login/oauth/access_token'
payload = {
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
'code': code,
# 'redirect_uri': REDIRECT_URI
}
headers = {'Accept': 'application/json'}
# 创建 POST 请求对象
request = Request.blank(token_url, method='POST',
POST=payload, headers=headers)
try:
# 发送请求
response = request.get_response()
except Exception as e:
LOG.error(e)
raise e
# 解析响应内容
if response.status_code == 200:
# print(response.json())
data = json.loads(response.text)
# access_token = data.get('access_token', None)
# if not access_token:
# # return 'Failed to retrieve access token'
# LOG.error('Failed to retrieve access token')
return data
else:
return None
改写为 在 cloudflare hono 框架下的函数
下面给出一个使用 Cloudflare Workers 上的 Hono 框架实现的等效函数示例。假设你已经在 Workers 的环境绑定(例如 secrets 或 environment variables)中配置了 CLIENT_ID
和 CLIENT_SECRET
,代码示例如下:
import { Context } from 'hono'
// 该函数处理 GitHub OAuth 回调,获取访问令牌
export async function getAccessToken(c: Context): Promise<Response> {
// 从查询参数中获取 code
const code = c.req.query('code')
if (!code) {
return c.text('Missing code', 400)
}
// 从环境变量中获取 GitHub 应用的 Client ID 与 Client Secret
const CLIENT_ID = c.env.CLIENT_ID
const CLIENT_SECRET = c.env.CLIENT_SECRET
const tokenUrl = 'https://github.com/login/oauth/access_token'
// 构造表单数据(application/x-www-form-urlencoded)
const params = new URLSearchParams()
params.append('client_id', CLIENT_ID)
params.append('client_secret', CLIENT_SECRET)
params.append('code', code)
// 如果需要,也可以加入 redirect_uri 参数
// params.append('redirect_uri', 'your_redirect_uri')
try {
// 发送 POST 请求获取访问令牌
const res = await fetch(tokenUrl, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
},
body: params.toString()
})
if (!res.ok) {
const errorMsg = await res.text()
console.error('Error fetching token:', errorMsg)
return c.json({ error: 'Failed to retrieve access token' }, res.status)
}
const data = await res.json()
return c.json(data)
} catch (error) {
console.error('Fetch error:', error)
return c.json({ error: 'Internal Server Error' }, 500)
}
}
@@@ 说明
- 获取参数与环境变量:函数首先从查询字符串中读取
code
,并从环境变量中获取CLIENT_ID
和CLIENT_SECRET
。在 Cloudflare Workers 中,这通常通过绑定(Bindings)实现。 - 构造请求:使用
URLSearchParams
构造表单数据,并设置请求头为application/x-www-form-urlencoded
以及Accept: application/json
(保证 GitHub 返回 JSON 格式的数据)。 - 错误处理:利用 try-catch 捕获请求异常,并在请求失败时返回相应的错误信息。
- 返回结果:请求成功后,解析 JSON 数据并返回。
将该函数添加到 Hono 应用中,比如:
import { Hono } from 'hono'
import { getAccessToken } from './your_module'
const app = new Hono()
// 设置回调路由,用户在 GitHub 授权后会跳转到此路由
app.get('/github-authenticate-callback', getAccessToken)
export default app
这样就完成了将原来的 Python 代码改写为 Cloudflare Hono 框架下的实现。
将原有的js 的 getAccessToken函数解耦,分为 响应路由 /github-authenticate-callback 的 handler 与获取 AccessToken 的 函数
下面给出一个将获取 AccessToken 的逻辑与响应路由处理解耦后的示例。示例中,我们将与 GitHub 通信获取 access token 的逻辑封装在一个独立的函数 fetchAccessToken
中,然后在路由处理函数 githubAuthCallbackHandler
中调用该函数。
@@@ tokenService.ts
// tokenService.ts
/**
* 该函数用于与 GitHub 交互,使用 code 获取 access token
* @param clientId GitHub App 的 Client ID
* @param clientSecret GitHub App 的 Client Secret
* @param code 授权回调中传回的 code
* @returns 返回解析后的 token 数据
*/
export async function fetchAccessToken(clientId: string, clientSecret: string, code: string): Promise<any> {
const tokenUrl = 'https://github.com/login/oauth/access_token'
const params = new URLSearchParams()
params.append('client_id', clientId)
params.append('client_secret', clientSecret)
params.append('code', code)
// 如果需要,加入 redirect_uri 参数
// params.append('redirect_uri', 'your_redirect_uri')
const res = await fetch(tokenUrl, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
},
body: params.toString()
})
if (!res.ok) {
const errorMsg = await res.text()
throw new Error(`获取 access token 失败:${errorMsg}`)
}
return res.json()
}
@@@ handler.ts
// handler.ts
import { Context } from 'hono'
import { fetchAccessToken } from './tokenService'
/**
* GitHub 授权回调路由处理函数
* 该函数从请求中提取 code,然后调用 fetchAccessToken 获取 token,并返回 JSON 响应
*/
export async function githubAuthCallbackHandler(c: Context): Promise<Response> {
// 从查询参数中获取 code
const code = c.req.query('code')
if (!code) {
return c.text('缺少 code 参数', 400)
}
// 从环境变量中读取 Client ID 与 Client Secret(需要在 Workers 中绑定)
const CLIENT_ID = c.env.CLIENT_ID
const CLIENT_SECRET = c.env.CLIENT_SECRET
try {
const tokenData = await fetchAccessToken(CLIENT_ID, CLIENT_SECRET, code)
return c.json(tokenData)
} catch (error) {
console.error('获取 access token 过程中出错:', error)
return c.json({ error: '获取 access token 失败' }, 500)
}
}
@@@ app.ts
// app.ts
import { Hono } from 'hono'
import { githubAuthCallbackHandler } from './handler'
const app = new Hono()
// 注册 GitHub 授权回调路由
app.get('/github-authenticate-callback', githubAuthCallbackHandler)
export default app
@@@ 说明
- 解耦设计:
fetchAccessToken
专注于与 GitHub 通信获取 token,而githubAuthCallbackHandler
负责处理路由请求、参数校验与错误处理。 - 环境变量:在 Cloudflare Workers 中,可以通过绑定的方式传入
CLIENT_ID
和CLIENT_SECRET
。 - 错误处理:当请求参数缺失或获取 token 失败时,分别返回相应的错误提示。
这样就实现了将原有的 getAccessToken 函数解耦,分别为响应路由处理和获取 AccessToken 的逻辑。
second example:
app.get('/github/auth', (c) => {
// 从环境变量中获取 GitHub Client ID
const clientId = c.env.GITHUB_CLIENT_ID
const githubAuthUrl = https://github.com/login/oauth/authorize?client_id=${clientId}
return c.redirect(githubAuthUrl)
})
解耦为路由注册 与 handler
下面是将路由注册与处理函数解耦的示例代码:
import { Hono } from 'hono'
import type { Context } from 'hono'
interface Env {
GITHUB_CLIENT_ID: string;
}
// 定义处理函数
const githubAuthHandler = (c: Context<{ Bindings: Env }>) => {
// 从环境变量中获取 GitHub Client ID
const clientId = c.env.GITHUB_CLIENT_ID
const githubAuthUrl = `https://github.com/login/oauth/authorize?client_id=${clientId}`
return c.redirect(githubAuthUrl)
}
// 注册路由
const app = new Hono()
app.get('/github/auth', githubAuthHandler)
export default app
@@@ 说明
- 处理函数解耦: 将 GitHub 授权重定向逻辑封装在
githubAuthHandler
函数中,路由注册时直接引用该处理函数。 - 环境变量绑定: 使用 TypeScript 的接口
Env
指定环境变量类型,确保在 Cloudflare Workers 部署时能正确获取GITHUB_CLIENT_ID
。