SvelteKit如何携带Access Token调用受SSO保护的外部API
SvelteKit对接SSO保护的Express API的鉴权方案
问题背景
现有一套基于Node.js Express搭建的API服务,支持图片、视频等多类型文件上传、获取,同时可返回标准JSON格式响应。需要将SvelteKit应用对接至该API,但这套API受SSO安全策略保护,所有请求必须携带有效访问令牌。
目前已在SvelteKit端通过OIDC协议的SSO流程成功获取访问令牌,先后尝试三种实现方案均存在缺陷:
- 方案一:通过Service Worker拦截所有发往目标API的请求,自动注入访问令牌
存在问题:Service Worker仅在生产构建环境生效,开发环境无法使用,每次调试都执行生产构建流程会大幅降低开发效率。 - 方案二:所有请求先发送至SvelteKit后端服务,由后端携带访问令牌转发至目标API
存在问题:该方案最初仅支持普通请求,不支持流传输;近期虽已有相关功能支持的进展,但缺乏官方文档与可参考的使用示例,同时会额外消耗服务端带宽与计算资源,理想状态下文件类请求应当直接从浏览器发往API端,不需要经过SvelteKit服务端中转。 - 方案三:使用Hooks中的
externalFetch能力,修改或替换服务端运行(含预渲染阶段)load函数内发起的外部资源fetch请求
存在问题:该能力无法覆盖图片src属性这类由浏览器直接发起的静态资源请求。
实测新版SvelteKit已将内置的node-fetch替换为Undici,流传输功能可正常使用,能够稳定实现后端请求转发,这种方式在开发环境下使用体验较好,但并非生产环境的最优方案,可根据运行环境组合使用不同方案。
推荐实现思路
采用环境分层+按请求类型分流的组合策略,兼顾开发体验、生产性能与鉴权安全性,不需要强制依赖单一方案:
基础层:统一请求封装
首先封装通用API请求客户端,覆盖所有主动发起的JSON请求、文件上传请求,自动注入访问令牌,避免重复写鉴权逻辑:
// src/lib/apiClient.js const API_BASE = import.meta.env.VITE_API_BASE; export async function apiRequest(path, options = {}) { const token = localStorage.getItem('sso_access_token'); return fetch(`${API_BASE}${path}`, { ...options, headers: { ...options.headers, Authorization: `Bearer ${token}` } }); }
开发环境:服务端代理兜底
开发环境优先保障热更效率,不启用Service Worker,用服务端转发覆盖所有场景:
- 所有
load函数内的数据请求,通过hooks.server.js中的externalFetch钩子自动注入服务端存储的SSO令牌,不需要额外业务代码处理 - 图片、视频这类由标签直接发起的静态资源请求,统一走SvelteKit通用代理路由,利用Undici的流能力直接透传API响应,不会把文件全量缓存到SvelteKit服务端内存,资源损耗极低。代理路由示例:
// src/routes/api/dev-proxy/[...path]/+server.js export async function GET({ params, request, locals }) { // 提前在hooks中从session解析出SSO令牌挂载到locals const token = locals.accessToken; const path = params.path; const search = request.url.split('?')[1] ? `?${request.url.split('?')[1]}` : ''; const targetRes = await fetch(`${import.meta.env.VITE_API_BASE}/${path}${search}`, { headers: { Authorization: `Bearer ${token}` }, duplex: 'half' }); return new Response(targetRes.body, { headers: targetRes.headers }); }
开发环境下静态资源的src属性统一指向该代理路由即可,不需要额外处理鉴权。
生产环境:客户端直连优先
生产环境优先保障性能,关闭服务端代理,启用Service Worker做全量请求拦截:
- 生产构建时自动注册Service Worker,拦截所有指向API域名的请求——不管是主动发起的fetch请求,还是img、video标签触发的静态资源请求,统一自动注入客户端存储的访问令牌,所有请求直连API服务,完全不占用SvelteKit服务端资源
- 增加降级逻辑:Service Worker未激活的极端场景(比如用户浏览器禁用SW、首次访问SW尚未注册完成),静态资源临时fallback到服务端代理路由,等SW激活后自动切回直连模式,保证页面可用性
边界场景处理
- 令牌过期:在请求客户端、Service Worker、代理路由三层统一拦截401响应,自动触发SSO令牌刷新流程,刷新失败则跳转SSO登录页
- 大文件上传:不管开发还是生产环境,大文件上传统一走客户端直传,通过封装的
apiRequest注入令牌,不经过代理,避免占用服务端带宽 - 预渲染页面:构建阶段预渲染的页面如果需要引用API静态资源,提前在
externalFetch钩子中完成鉴权拉取资源,做静态化处理,用户访问时不需要额外请求API
内容的提问来源于stack exchange,提问作者Jija
相关产品推荐
相关产品推荐

