Puter.js 登录状态检测指南:读懂 puter.auth.isSignedIn() 的前世今生与实战用法
【免费下载链接】puter🌐 The Internet Computer! Free, Open-Source, and Self-Hostable.项目地址: https://gitcode.com/GitHub_Trending/pu/puter
puter.auth.isSignedIn()是 Puter.js 认证模块中用于同步判断当前用户是否已登录的最轻量接口。无论你的应用运行在第三方网站上、Puter 平台内(App)、Node.js 还是 Worker 运行时,它都能在不发起任何网络请求、不弹出任何登录框的前提下,立即返回一个布尔值,是编写"登录门控"逻辑最常用的一把钥匙。读完本文,你将掌握该 API 的语法细节、它与signIn()/signOut()/getUser()的分工关系,以及隐藏在源码与测试背后的完整 token 生命周期。
速览:语法、参数与返回值
该 API 定义于官方文档 Auth/isSignedIn.md,其元信息声明支持的平台为websites、apps、nodejs、workers四类运行时。
语法
puter.auth.isSignedIn()参数
无。
返回值
- 用户当前已登录:返回布尔值
true; - 用户未登录:返回布尔值
false。
它不会像puter.auth.getUser()那样发起/whoami请求,也不会像puter.auth.signIn()那样打开授权弹窗,因此可以放心地在页面渲染、按钮状态切换等同步上下文中调用。
可直接运行的示例(官方文档原样示例):
<html> <body> <script src="https://js.puter.com/v2/"></script> <script> puter.print(`Sign in status: ${puter.auth.isSignedIn()}`); </script> </body> </html>说明:
https://js.puter.com/v2/是 Puter.js 官方托管的 SDK 入口。如果部署的是自托管环境,也可以基于仓库内 src/puter-js 自行构建并托管该 SDK,页面加载逻辑一致。
底层实现:为什么它是纯同步判断
要理解isSignedIn()的语义,最直接的方式是阅读其源码实现。该方法是 Auth 模块 中一个极简的箭头函数:
/** * Whether the user is currently signed in. * * @type {() => boolean} */ isSignedIn = () => { if ( puter.authToken ) { return true; } else { return false; } };(见 Auth.js)
从源码可以看出两个关键事实:
- 它判断的是"客户端是否持有一个非空的 authToken",而非"服务端是否认可这个 token"。这个
authToken是 SDK 在内存中维护的登录凭证(index.js 中初始化为authToken = null)。 - 它是同步方法:内部只是做一次真值判断,没有任何 Promise、XHR 或弹窗逻辑,因此永远不会因为网络延迟而阻塞,也永远不会被浏览器拦截。
与它形成对比的是同模块内的getUser()/whoami():这两个方法会真正调用后端/whoami接口去拉取用户资料,并且在没有 token 时立刻抛错(伪造服务端响应{ status: 401, message: 'Unauthorized' },见 Auth.js)。而 SDK 的注释也明确指出:"需要确定答案(且接受随之而来的登录提示)的调用方应使用puter.auth.getUser()"——换句话说,isSignedIn()适合"只想安静地问一句、不想打扰用户"的场景。
authToken 从哪来:一次完整的登录状态生命周期
既然isSignedIn()只是检查puter.authToken,那么理解"这个 token 什么时候被写入、什么时候被清除",就等于理解了该 API 的全部行为边界。
1. 通过 signIn() 弹窗写入
在第三方网站上(SDK 内部称之为env = 'web'),登录通常由 signIn 文档 描述的puter.auth.signIn()驱动:它打开 Puter GUI 的授权弹窗,用户完成登录后,弹窗通过postMessage回传puter.token消息,SDK 校验消息来源(必须是defaultGUIOrigin、来源窗口必须是它自己打开的弹窗、msg_id必须匹配)后调用puter.setAuthToken(e.data.token)写入 token,随后resolve。此时再调用isSignedIn()就会返回true。
2. 页面刷新后从 localStorage 恢复
SDK 启动引导逻辑(index.js)会根据运行环境恢复会话:
- 在web 环境下,token 持久化于 localStorage,键名为
puter.auth.token.v2(旧版本遗留键puter.auth.token只删不读,见 index.js); - 恢复 token 前会校验其绑定的 API origin(
STORAGE_KEY_ORIGIN_V2),只把 token 重放到它签发时对应的 origin,防止 URL 可控的puter.api_origin窃取其他站点存储的凭证; - 在app 环境下,SDK 被 Puter GUI 以启动参数
?puter.auth.token=...方式拉起,token 由启动它的 Puter 会话直接提供; - 在gui 环境下(SDK 运行在 Puter 桌面本身),token 直接取自
window.auth_token。
因此,"上次登录过、今天刷新页面后isSignedIn()依然返回true"这个用户体验,正是由这套引导恢复逻辑保证的。
3. 通过 signOut() 清除
signOut 文档 描述的puter.auth.signOut()内部调用puter.resetAuthToken()(见 Auth.js),该方法会清空内存 token 并同步删除 localStorage 中的持久化 token,随后isSignedIn()立即返回false。需要留意:resetAuthToken在web-worker/service-worker环境下会直接抛错拒绝登出(见 index.js),所以 Worker 运行时中的会话是"无法自行登出"的。
4. token 被后端判定失效时被清除
isSignedIn()只检查本地 token 是否存在,并不保证该 token 在服务端仍然有效。若 token 已过期或被吊销,下一次 API 调用会收到 401,此时 SDK 的网络层会触发reauth 协调流程:先丢弃这个"中毒"的 token(authToken置回null),再按环境决定是弹出登录框还是抛出结构化的reauth_required错误。也就是说,一个失效会话在 reauth 触发并完成前,isSignedIn()可能短暂地仍返回true;而在 reauth 丢弃 token 之后,它会恢复为false。该行为由测试用例a token the backend rejects routes through reauth与reauth is a no-op inside the Puter GUI显式验证(见 auth.suite.ts)。
实战:用 isSignedIn() 搭建登录门控界面
把上述 API 组合起来,就能写出一个结构完整、可直接复制到任意 HTML 页面中的登录/登出门控示例。下面这个示例继承并扩充了官方文档中的 auth-is-signed-in 示例:初次加载时根据登录状态渲染不同按钮,点击登录按钮完成signIn()后刷新状态,点击登出按钮后回到未登录视图。
<html> <body> <script src="https://js.puter.com/v2/"></script> <div id="app"> <p id="status">Loading…</p> <button id="sign-in" style="display:none">Sign in with Puter</button> <button id="sign-out" style="display:none">Sign out</button> </div> <script> function render() { const signedIn = puter.auth.isSignedIn(); document.getElementById('status').textContent = signedIn ? 'Signed in' : 'Not signed in'; document.getElementById('sign-in').style.display = signedIn ? 'none' : 'inline-block'; document.getElementById('sign-out').style.display = signedIn ? 'inline-block' : 'none'; } // signIn() 必须由用户手势(如点击)触发,否则浏览器会拦截弹窗。 document.getElementById('sign-in').addEventListener('click', async () => { try { const res = await puter.auth.signIn(); console.log('Signed in as', res.username); } catch (err) { // 可能的错误:popup_blocked / auth_window_closed / not_available_in_app console.error(err.error, err.msg); } render(); }); document.getElementById('sign-out').addEventListener('click', () => { puter.auth.signOut(); render(); }); render(); </script> </body> </html>当希望进一步展示用户信息时,可在isSignedIn()返回true后调用puter.auth.getUser()(或等价的puter.auth.whoami())获取uuid、username等资料;用户对象字段的完整定义可查看 Auth.js 顶部的 JSDoc。
边界与陷阱小结
围绕isSignedIn(),有几点值得在生产代码中注意:
| 场景 | 表现 | 依据 |
|---|---|---|
| 从第三方网站发起登录 | 必须由点击等用户手势调用signIn(),否则弹窗被拦截,rejectpopup_blocked | signIn.md |
在 Puter 平台 App 内调用signIn() | 直接 rejectnot_available_in_app,App 的 token 由启动它的会话提供;此时应直接使用getUser() | Auth.js |
在 Worker 内调用signOut() | 抛错拒绝,会话无法自行登出 | index.js |
| token 过期/被吊销 | isSignedIn()的本地判断与服务端实际校验存在时间差;依赖服务端判定时请使用会真实请求/whoami的getUser() | auth.suite.ts |
| 需要静默体验(临时用户) | signIn({ attempt_temp_user_creation: true })可为用户自动创建临时账号,无需注册即可完成登录 | signIn.md |
测试验证:这些行为是如何被保证的
仓库为认证模块提供了多层测试,可作为行为契约参考:
- 单元/集成测试 auth.suite.ts 中,用例
isSignedIn reports true with a valid token断言持有合法 token 时返回true;signOut clears the session client-side断言登出后返回false并可在重新写入 token 后恢复;signOut is refused in every worker environment则验证在web-worker、service-worker下被拒绝的登出不会破坏原有登录状态(见 auth.suite.ts)。 - 跨域交互测试 signin.test.js 中,
testSignInPostMessage在完成一次真实的弹窗登录后断言:SDK 采纳了返回的 token,且puter.auth.isSignedIn()在成功登录后为真(见 signin.test.js)。该测试需在非 Puter GUI 源下手动逐条运行。
相关 API 导航
puter.auth.isSignedIn()只是认证模块的一个成员。完整的认证能力由以下几部分组成:
- Auth.md——认证模块总览,涵盖全部功能与聚合示例;
- signIn.md——发起登录(仅限网站平台,需用户手势触发);
- signOut.md——登出当前用户;
- getUser.md——获取当前登录用户信息;
- getMonthlyUsage.md 与 getDetailedAppUsage.md——查询月度资源用量与单应用用量明细。
在动手之前,请记住最核心的一条心法:大多数 Puter.js 方法都会自动完成鉴权,isSignedIn()是少数需要你主动调用的"体检式"接口——它只负责告诉你本地的钥匙在不在,而真正开门验证身份的,是那些带网络请求的方法。
【免费下载链接】puter🌐 The Internet Computer! Free, Open-Source, and Self-Hostable.项目地址: https://gitcode.com/GitHub_Trending/pu/puter
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考