无第三方服务的PWA离线认证方案及Firefox缓存兼容问题
PWA离线认证与缓存兼容问题
我正在开发一款支持离线运行的Progressive Web App(PWA),目前已成功实现卡组(decks)和卡片(cards)的缓存离线访问,但在用户进入应用时的初始认证环节遇到了问题:应用会请求/getuser接口,若用户处于离线状态则无法完成认证。
我当前的解决方案是缓存/getuser请求,从缓存中获取认证信息,但不确定这是否为安全的行业级方案。此外,该策略在Chrome中运行正常,但在Firefox中不符合预期:当用户会话过期后,Firefox会将该状态缓存,即便用户在线且已登录,仍会返回缓存的过期数据,导致已登录用户被重定向到会话过期页面,尽管我采用的是NetworkFirst缓存策略。
使用vite-plugin-pwa库配置Service Worker的代码如下:
import { defineConfig, loadEnv } from 'vite' import react from "@vitejs/plugin-react-swc"; import { VitePWA } from "vite-plugin-pwa"; export default defineConfig(({ command, mode }) => { // In vite.config.ts we can't access env variables using import.meta.env.VITE_API_URL we have to use following code to access it. const env = loadEnv(mode, process.cwd()) const API_URL = `${env.VITE_API_URL}` return { plugins: [react(), VitePWA({ registerType: 'autoUpdate', devOptions: { enabled: true }, injectRegister: 'auto', // add this to cache all the imports workbox: { globDirectory: "dist", globPatterns: ["**/*",], runtimeCaching: [ { urlPattern: new RegExp(`${API_URL}/decks$`), // your API endpoint handler: 'NetworkFirst', // caching strategy options: { cacheName: 'decks-cache', expiration: { maxEntries: 1, // number of entries to store maxAgeSeconds: 60 * 60 * 24 * 7, // cache expiration time }, cacheableResponse: { statuses: [200] } }, }, { urlPattern: new RegExp(`${API_URL}/cards/.+`), handler: 'NetworkFirst', // Caching strategy for /cards/deck_id options: { cacheName: 'cards-cache', expiration: { maxEntries: 500, maxAgeSeconds: 60 * 60 * 24 * 7, // cache expiration time }, cacheableResponse: { statuses: [200], }, }, }, { urlPattern: new RegExp(`${API_URL}/decks-and-cards$`), handler: 'NetworkFirst', options: { cacheName: 'search-cache', expiration: { maxEntries: 500, maxAgeSeconds: 60 * 60 * 24 * 7, // cache expiration time }, cacheableResponse: { statuses: [200], }, }, }, { urlPattern: new RegExp(`${API_URL}/getuser$`), handler: 'NetworkFirst', options: { cacheName: 'auth-cache', expiration: { maxEntries: 500, maxAgeSeconds: 60 * 60 * 24 * 7, // cache expiration time }, cacheableResponse: { statuses: [200], }, }, }, ] }, // add this to cache all the // static assets in the public folder includeAssets: [ "**/*", ], manifest: { .... } }),], } })
问题
- 不依赖第三方服务的PWA离线认证,更安全的行业标准方案是什么?
- 缓存
/getuser请求是否为推荐方案? - 如何解决Firefox中的缓存兼容问题?
解答
1. 不依赖第三方服务的PWA离线认证标准方案
核心采用本地轻量身份存储+离线权限降级的模式,具体实施:
- 服务器端使用HttpOnly、Secure的Cookie存储会话ID,前端仅在
localStorage/sessionStorage中存储非敏感的用户元数据(如用户ID、昵称、基础权限标记),绝不存储密码、完整权限列表等敏感信息。 - 离线状态下,通过本地存储的元数据快速完成身份识别,仅开放用户已缓存的私有数据访问权限,禁止所有需要服务器交互的操作(如修改数据、同步新内容)。
- 在线状态下,优先调用
/getuser接口校验会话有效性:若会话过期则清除本地存储并引导登录;若有效则更新本地存储的用户信息。 - 给本地存储的身份元数据设置过期时间,超过时限后即使用户离线也要求重新登录,在线时自动刷新过期时间。
2. 是否推荐缓存/getuser请求?
不推荐直接缓存/getuser接口的响应,原因如下:
- 安全风险:缓存的响应可能包含敏感用户信息,一旦本地缓存被窃取会导致信息泄露;且缓存状态无法实时同步服务器的会话过期/注销操作。
- 逻辑冲突:会出现像Firefox中那样,缓存的过期状态覆盖在线有效会话,导致用户体验异常。
- 替代方案:改为缓存轻量化的用户身份元数据,仅用于离线时快速识别用户并开放缓存数据访问,在线时始终优先请求服务器校验会话。
3. Firefox缓存兼容问题的解决办法
针对Firefox中NetworkFirst策略失效的问题,可从以下几点调整:
(1)优化缓存策略配置
修改/getuser的缓存规则,缩短缓存有效期、添加缓存校验逻辑,避免无效状态被长期缓存:
{ urlPattern: new RegExp(`${API_URL}/getuser$`), handler: 'NetworkFirst', options: { cacheName: 'auth-cache', expiration: { maxEntries: 1, // 仅保留最新1条缓存,避免多状态冲突 maxAgeSeconds: 60 * 15, // 缩短缓存有效期至15分钟 }, cacheableResponse: { statuses: [200], // 仅缓存成功认证的响应,不缓存未授权状态 }, fetchOptions: { credentials: 'include', }, plugins: [ { cacheWillUpdate: async ({ response }) => { // 校验响应是否为有效认证状态,仅此时缓存 const data = await response.clone().json(); return data.isAuthenticated ? response : null; }, }, ], }, }
(2)在线请求强制绕过缓存
前端调用/getuser接口时,添加cache: 'no-store'选项,确保在线请求直接访问服务器:
fetch('/api/getuser', { credentials: 'include', cache: 'no-store' // 强制不使用缓存 })
(3)主动清除认证缓存
当用户执行登录、注销操作时,主动调用API删除auth-cache中的缓存条目:
if ('caches' in window) { caches.delete('auth-cache').then(() => { console.log('认证缓存已清除'); }); }
内容的提问来源于stack exchange,提问作者Max Vhanamane
相关产品推荐
相关产品推荐

