import assert from 'node:assert/strict' import { createRequire } from 'node:module' /** * 小程序鉴权契约守卫 * * 覆盖三类此前只在真机/开发者工具上才会暴露的缺陷(2026-09-22 首页 401 事故): * 1. hydrate:没有 access token 时不得恢复登录态。 * 2. 登录/刷新:后端返回字段是 accessToken(不是 token),若字段名写错, * token 永远写不进 storage → 每个请求都不带 Authorization → 全站 401。 * 3. 刷新:后端 /auth/refresh 需要 userId(用于定位 Redis 中的 refresh token), * 缺失会直接 400,导致刷新失败、登录态被误清。 */ const removed = [] const storage = {} globalThis.wx = { getStorageSync(key) { if (key in storage) return storage[key] if (key === 'isLoggedIn') return { isLoggedIn: true, userId: 'stale-user' } return '' }, setStorageSync(key, value) { storage[key] = value }, removeStorageSync(key) { removed.push(key) delete storage[key] }, } const require = createRequire(import.meta.url) // ---- 1. hydrate:无 token 不得恢复登录态 ---- const authStore = require('../miniapp/stores/authStore.js') authStore.hydrate() assert.equal(authStore.state.isLoggedIn, false, '没有 access token 时不得恢复登录态') assert.ok(removed.includes('isLoggedIn'), '应清理失真的登录快照') const api = require('../miniapp/utils/api.js') // ---- 2. 登录:必须持久化 accessToken(后端字段名为 accessToken)---- api.post = async () => ({ accessToken: 'ACC-1', refreshToken: 'REF-1', userId: 'u-1', expiresIn: 7200 }) await authStore.loginWithWechat('wx-code') assert.equal( storage.accessToken, 'ACC-1', '登录后必须把后端返回的 accessToken 写入 storage(字段名写成 token 会落空 → 全站 401)', ) assert.equal(storage.refreshToken, 'REF-1', '登录后必须写入 refreshToken') // ---- 3. 刷新:必须带 userId + refreshToken,并持久化新的 accessToken ---- let refreshBody = null api.post = async (url, body) => { if (url === '/auth/refresh') { refreshBody = body return { accessToken: 'ACC-2', refreshToken: 'REF-2', expiresIn: 7200 } } return {} } await authStore.refresh() assert.ok(refreshBody, '刷新必须发起 /auth/refresh 请求') assert.equal( refreshBody.userId, 'u-1', '刷新请求必须携带 userId(后端据此定位 Redis refresh token,缺失会返回 400)', ) assert.equal(refreshBody.refreshToken, 'REF-1', '刷新请求必须携带 refreshToken') assert.equal(storage.accessToken, 'ACC-2', '刷新成功后必须持久化新的 accessToken') console.log('Miniapp auth contracts passed')