☰
ChatGPT-Shortcut(AiShort)账户体系详解:Google 登录、免密链接登录与账户数据管理的源码级实现
2026/9/25 10:51:53 网站建设 项目流程
  • AI 应用
  • 提示工程
  • 人工智能
  • 前端

【免费下载链接】ChatGPT-Shortcut

Stop writing prompts from scratch — a searchable prompt library for ChatGPT, Claude, Gemini and Cursor · Русский 한국어 العربية हिन्दी ไทย | 别再从头写提示词:现成的拿来就用,好用的收进自己的库

项目地址:https://gitcode.com/gh_mirrors/ch/ChatGPT-Shortcut
点击查看免费下载

ChatGPT-Shortcut(AiShort)是一个可搜索的提示词库,支持 ChatGPT、Claude、Gemini 与 Cursor 等多个 AI 工具。它允许匿名使用,但只有登录后才能收藏提示词、创建自定义提示词、分享到社区并在多台设备间同步「我的收藏」。本文基于仓库中的账户指南文档(i18n/de/docusaurus-plugin-content-docs/current/guides/account.md)与对应前端源码,完整讲解三种登录方式、注册流程、「我的账户」页面的个人资料与密码管理、L0–L9 等级体系,以及数据导出/导入/缓存清除的实现细节,帮助读者既会用这些功能,又理解它们背后的 API 调用链与本地缓存机制。

为什么账号是可选的

站点本身是无账号可用的:浏览提示词、搜索、复制提示词都不需要登录。登录的价值在于:

  • 收藏精选提示词与社区提示词到「我的收藏」;
  • 创建、编辑、删除自己的自定义提示词(可公开分享或设为私密);
  • 将上述数据按账户存储,实现跨设备、跨浏览器同步。

从前端结构看,整个身份体系围绕 src/components/AuthContext.tsx 展开:登录成功后 JWT 写入localStorage的auth_token,AuthProvider 再拉取/myspace等用户数据并维护全局状态;页面组件(收藏视图、用户中心)都从该 Context 读取。

三种登录方式

登录对话框提供「密码登录」和「免密登录」两个 Tab,外加一键 Google 登录。在 src/components/user/login.tsx 中,对话框通过viewState(login/register/forgot-password)和loginType(password/code)两个状态切换不同表单视图,所有请求最终汇聚到 src/api/auth.ts 导出的接口函数。

密码登录

使用用户名或注册邮箱 + 密码登录。对应源码为login():

export async function login(values: { username: string; password: string }) { const response = await apiClient.post(`/auth/local`, { identifier: values.username, password: values.password, }); clearUserCachesOnLogin(); // 清除旧用户的 USER_PROFILE 与 MySpace 缓存 return response; }

两个实现细节值得注意:

  1. identifier 即用户名或邮箱——接口不区分二者,用户填哪个后端都能识别,这与 UI 中「用户名/邮箱」的占位符提示一致;
  2. 登录后先清缓存——clearUserCachesOnLogin()会同时清掉USER_PROFILE与MySpace两块本地缓存,防止上一个账号的残留 ETag 与新账号巧合命中(源码注释明确指出这是为避免旧账号数据串到新账号)。

登录成功后 src/components/user/login.tsx 中的handleSuccess会:把 JWT 存入localStorage("auth_token"),通过window.postMessage向浏览器扩展页发送{ action: "login", username, jwt }消息(让浏览器扩展也能感知登录状态),然后刷新页面。

免密登录(登录链接)

适合「只是偶尔登录一次」的用户,无需记忆密码:

  1. 切到「免密登录」Tab,输入注册邮箱(或用户名);
  2. 点击「获取登录链接」,系统向你的邮箱发送一条登录链接;
  3. 点击邮件中的链接完成登录。

源码上有两点比文档更细:

  • 前端 src/components/user/login.tsx 的handleSendPasswordlessLink会用正则/\S+@\S+\.\S+/判断输入是否为邮箱格式:是邮箱就发{ email },不是就发{ username },所以用户名同样能收到登录链接;
  • 接口分两步:sendPasswordlessLink()向POST /passwordless/send-link发请求取链接;用户点击邮件中的链接后,页面携带loginToken调loginWithToken()执行GET /passwordless/login?loginToken=...,拿回jwt后同样执行persistAuthToken+ 清缓存,与密码登录走同一条状态落地路径。

Google 一键登录

在登录对话框点击「Login via Google」即可;首次通过 Google 登录时系统会自动为你创建账户,无需单独注册。

从 src/api/auth.ts 的实现看,Google 登录是一个完整的 OAuth 重定向流程,且由USE_LEGACY_GAUTH开关(见 src/api/config.ts)在两套后端流程间切换:

配置流程
USE_LEGACY_GAUTH = false(当前默认)前端拼接${GAUTH_API_BASE}/api/connect/google?redirect=<origin>/user/auth,由 Strapi 原生 OAuth 路由接管,回调时把jwt与user带回前端
USE_LEGACY_GAUTH = true(旧版)先请求/strapi-google-auth/init获取跳转 URL;授权后用code调/strapi-google-auth/user-profile换取 token,再调/me拉取用户信息

关键常量与路径(均来自 src/api/config.ts 与 src/api/auth.ts):

export const API_URL = "https://api.newzone.top/api"; // 主 API(Strapi 后端) export const GAUTH_API_BASE = "https://gauth.aishort.top"; // Google OAuth 入口服务 export const USE_LEGACY_GAUTH = false;

配置注释解释了为什么需要独立的gauth服务:主服务器所在网络无法直连 Google,因此 OAuth 入口被拆到独立域名。前端侧,handleGoogleLogin会打开一个 520×570 的弹出窗口展示加载动画,跳转到认证 URL;授权完成后window的message事件监听器捕获回传的jwt/access_token/code等载荷,调用googleLogin()完成认证。若弹窗被浏览器拦截,会提示「Pop-up window blocked」。

登录态的本地校验

JWT 并非「存了就算数」。src/components/AuthContext.tsx 中的isValidToken会在本地解码 JWT 的payload.exp并与当前时间比较(预留 60 秒时钟偏差余量):过期的 token 会被直接删除并视为未登录,避免拿着失效凭证反复请求后端;解析失败时则保守地认为有效,防止误登出。此外 AuthProvider 采用 stale-while-revalidate 策略——刷新页面时先用本地缓存的user_auth立即渲染,避免登录状态「闪烁」。

注册账户

  1. 在登录对话框点击「立即注册」切到注册视图;
  2. 填写用户名、邮箱、密码,并勾选同意服务条款与隐私政策;
  3. 提交后自动完成登录。

表单校验规则(src/components/user/login.tsx 顶部的rules)给出了具体约束:

  • 用户名必填;
  • 密码必填且至少 6 个字符;
  • 邮箱必填且需通过邮箱格式校验;
  • 注册必须勾选同意框,否则报错「使用前须同意服务条款和隐私政策」。

注册请求由 src/api/auth.ts 的register()发出:POST /auth/local/register,载荷为{ username, email, password }。与密码登录复用同一个handleAuth成功处理器——返回的jwt落盘、postMessage通知扩展、500ms 后刷新页面,所以注册完即处于登录态。

我的账户页面

登录后进入「我的账户」页(src/pages/user/index.tsx),页面未加载到用户信息时会在 2 秒后自动跳回首页(即未登录访问会重定向)。页面分为三块:用户信息、安全设置、数据管理。

修改用户名

点击用户名旁的编辑图标,输入新用户名并点保存。源码对应submitNewUsername:调用 src/api/user.ts 的updateUsername(),即PUT /favorites/update-username,载荷{ newUsername };成功后重新拉取用户信息刷新页面。接口名带favorites前缀,可以推断后端把「显示名」归在收藏/社区可见性相关的控制器里管理,改名会同步影响该用户提示词在社区的展示。

修改密码与忘记密码

修改密码三步:填写当前密码 → 填写并确认新密码 → 点「修改密码」,对应 src/api/auth.ts 的changePassword():POST /auth/change-password,载荷为{ currentPassword, newPassword, confirmPassword }(其中新密码以password与passwordConfirmation两个字段提交)。

这里有一个源码中才能发现的细节:src/pages/user/index.tsx 中「当前密码」输入框只在userInfo?.provider === "local"时渲染。也就是说,通过 Google 登录的账户(provider 不是 local)修改密码时无需填写当前密码,只需设置新密码——这也意味着 Google 账户可以「补一个密码」,之后即可用密码登录。

忘记密码有两条入口:登录对话框的「忘记密码」,以及「我的账户 → 安全设置」右上角的「忘记密码」按钮。两者都调用 src/api/auth.ts 的forgotPassword()(POST /auth/forgot-password)向注册邮箱发送重置邮件,然后点击邮件中的链接,由 src/pages/reset-password.tsx 页面处理最终重置,对应resetPassword():POST /auth/reset-password,载荷{ code, newPassword, confirmPassword },其中code来自邮件链接。

等级体系:L0–L9

账户页会展示你的Level(L0–L9)与升到下一级的进度。等级由你分享到社区的提示词数量决定——注意统计的是share为真的自定义提示词(src/pages/user/index.tsx 中userprompts.filter((p) => p.share).length),收藏数、浏览数都不计入。

具体阈值曲线定义在 src/components/LevelSystem.tsx:

export const LEVEL_THRESHOLDS = [0, 1, 3, 8, 18, 35, 60, 100, 160, 260];
等级名称所需分享提示词数
L0萌新探索者0
L1青铜≥ 1
L2白银≥ 3
L3黄金≥ 8
L4铂金≥ 18
L5钻石≥ 35
L6蓝宝石≥ 60
L7红宝石≥ 100
L8翡翠≥ 160
L9星辉≥ 260

相邻等级跨距依次为 1、2、5、10、17、25、40、60、100,约 1.6–2 倍递增,曲线平滑;L9 被定位为「传奇」档。页面显示的进度百分比为min(100, sharedCount / next * 100);达到 L9 后显示「MAX REACHED」。等级图标是一组随等级累积几何元素的 SVG 多边形(src/components/LevelSystem.tsx 的LevelIcon),L7 加中心圆点、L8 加粗描边、L9 加 8 条辐射线,纯 stroke 绘制、跨平台不依赖 emoji 字体。

数据管理

「我的账户 → 数据管理」提供三个操作:清除缓存、导出提示词、导入提示词。

清除缓存

点击「清除所有缓存」(带二次确认弹窗)会执行 src/pages/user/index.tsx 的handleClearCache:

clearUserProfileCache(); // 清除 USER_PROFILE 缓存 clearMySpaceCache(); // 清除 MYSPACE 缓存 await fetchUserInfo(); // 重新拉取用户数据

它只刷新本地缓存,不会删除任何服务端数据:收藏与自定义提示词都保存在账户里,清缓存只是丢弃浏览器里的旧副本并重新同步。文档建议的使用场景正是「数据不同步或显示异常」时的第一步自救——因为前端大量使用 ETag + TTL 缓存(见 src/api/user.ts 中getUserAllInfo对If-None-Match/ 304 的处理),偶发不一致时清缓存可强制重新协商。

导出提示词

点「导出数据」生成一个 JSON 文件并自动下载,文件名形如my-prompts-2026-09-24.json(当天日期)。src/pages/user/index.tsx 的handleExportPrompts会先批量拉取自定义提示词、收藏的精选卡(cards)与社区提示词(commus)的完整数据,再组装导出结构:

{ "exportTime": "ISO8601 时间戳", "prompts": [ // 全部自定义提示词 { "id": 1, "title": "…", "prompt": "…", "remark": "…", "notes": "…", "share": true } ], "favorites": { "card": [3, 7], "community": [12] }, // 收藏 ID 列表(导入用) "favoriteDetails": [ /* 收藏的详细内容,仅供人工查看,导入时忽略 */ ], "myspaceOrder": [ /* MySpace 卡片顺序,type/source/id 三元组 */ ], "customTags": [ /* 自定义标签定义 */ ] }

字段含义上值得注意:prompts里prompt字段对应后端存储的description,share表示该提示词是否已分享到社区;favoriteDetails与myspaceOrder、customTags是备份性质的快照,当前联网版导入时不会用它们恢复排序与标签(源码注释解释了原因:排序/标签中的 ID 属于源用户,覆盖式写入会破坏目标用户已有的体系)。

导入提示词

选择 JSON 文件导入,handleImportPrompts的实现比文档描述复杂得多,兼容三种输入格式:

  1. 纯数组:[ { title, prompt, … } ];
  2. 对象:{ prompts: [...], favorites: { card: [], community: [] } }(即导出文件本身);
  3. 单个提示词对象:{ title, prompt|description }。

规范化时以prompt || description作为正文,过滤掉缺title或缺正文的条目。冲突处理策略分四种情形:

情形行为
有id且属于当前用户,内容与现有完全一致跳过(skipped)
有id且属于当前用户,内容有差异按id更新该提示词
无id新建,share默认取文件值,缺省为公开(true)
有id但不属于当前用户作为新的私密提示词创建(share: false),防止误覆盖他人数据

收藏导入采用增量合并:只把本地不存在的favorites.card/favorites.communityID 通过PATCH /favorites(loves.add/commLoves.add)合并进现有收藏,不做删除,且服务端按 merge 语义处理以保证多设备并发安全。全部任务用Promise.allSettled并发执行,完成后汇总「成功 / 跳过 / 失败」数量并给出「全部成功」「部分导入成功 (x/y)」「导入失败」三档提示,最后调用refreshUserAuth()刷新 MySpace 视图。

小结:账户数据流全景

把本文涉及的端点串起来,AiShort 账户体系的完整调用链为:

  • 认证:POST /auth/local/register(注册)、POST /auth/local(密码登录)、POST /passwordless/send-link+GET /passwordless/login(免密)、GET /api/connect/google(OAuth)、POST /auth/change-password、POST /auth/forgot-password+POST /auth/reset-password;
  • 账户数据:GET /users/me(ETag 缓存)、PUT /favorites/update-username(改名)、GET /myspace(收藏 + 自定义提示词聚合);
  • 前端职责:JWT 本地过期校验、Stale-While-Revalidate 缓存、登录后强制清缓存、乐观更新 + 失败回滚。

所有认证请求集中封装在 src/api/auth.ts,端点基址集中在 src/api/config.ts,便于整体替换后端;页面层则分别是 src/components/user/login.tsx(登录/注册/忘记密码对话框)与 src/pages/user/index.tsx(我的账户)。

相关文档

  • 入门指南:基本使用方法
  • 我的收藏:收藏与自定义标签管理
  • 自定义提示词:创建、编辑、分享与导出提示词
  • AI 应用
  • 提示工程
  • 人工智能
  • 前端

【免费下载链接】ChatGPT-Shortcut

Stop writing prompts from scratch — a searchable prompt library for ChatGPT, Claude, Gemini and Cursor · Русский 한국어 العربية हिन्दी ไทย | 别再从头写提示词:现成的拿来就用,好用的收进自己的库

项目地址:https://gitcode.com/gh_mirrors/ch/ChatGPT-Shortcut
点击查看免费下载

相关推荐

上一篇:告别游戏窗口边框:Borderless Gaming 终极使用指南
下一篇:Wasp 语言(.wasp DSL)完全指南:声明式配置与类型系统深度解析

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询