VueJS微前端场景下如何模块化JavaScript认证代码
微前端Vue应用中心化认证方案(容器传递认证能力)
针对你的场景,推荐采用容器传递封装后的认证能力+子应用API单例注入的方案,既满足中心化认证的要求,又能避免子应用与Vue强绑定,具体实现如下:
核心思路
容器应用封装MSAL的核心认证方法(而非暴露整个上下文),通过single-spa的customProps传递给子应用;子应用创建独立的API单例,在bootstrap阶段注入认证能力,所有API请求统一通过该单例发起,自动处理token刷新。
1. 容器端:封装认证能力并传递给子应用
容器初始化MSAL后,不要直接传递整个AuthenticationContext,而是封装成子应用需要的极简接口(比如获取token、获取当前账户),通过挂载子应用时的customProps传递:
// 容器应用 - 子应用注册逻辑 import { PublicClientApplication, InteractionRequiredAuthError } from '@azure/msal-browser'; // 初始化MSAL(容器端仅做一次) const msalInstance = new PublicClientApplication({ auth: { clientId: '你的Azure AD客户端ID', authority: 'https://login.microsoftonline.com/你的租户ID' } }); // 封装认证服务 const authService = { // 获取token(自动处理静默刷新,失败则弹窗交互) acquireToken: async (scopes) => { try { const activeAccount = msalInstance.getActiveAccount(); const response = await msalInstance.acquireTokenSilent({ scopes, account: activeAccount }); return response.accessToken; } catch (error) { if (error instanceof InteractionRequiredAuthError) { const response = await msalInstance.acquireTokenPopup({ scopes }); return response.accessToken; } throw error; } }, // 获取当前登录账户(可选) getCurrentAccount: () => msalInstance.getActiveAccount() }; // 注册子应用时传递authService singleSpa.registerApplication({ name: '@your-org/sub-app', app: () => System.import('@your-org/sub-app'), activeWhen: ['/sub-app'], customProps: () => ({ authService }) });
2. 子应用:创建API单例并注入认证能力
子应用无需存储任何Azure AD配置,只需要创建独立的API模块,在single-spa的bootstrap阶段注入容器传递的authService:
第一步:创建独立的API模块(与Vue解耦)
// 子应用 src/utils/api.js let authService = null; // 初始化API,注入认证服务 export const initApi = (service) => { authService = service; }; // 基础请求方法(自动添加Bearer token) export const apiRequest = async (url, options = {}) => { if (!authService) { throw new Error('API未初始化:缺少authService'); } // 根据编排层API的scope获取token const token = await authService.acquireToken(['api://your-orchestration-layer/access']); // 组装请求头 const headers = { ...options.headers, 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }; return fetch(url, { ...options, headers }).then(res => { if (!res.ok) throw new Error(`请求失败:${res.status}`); return res.json(); }); }; // 具体业务API示例 export const getOrchestrationData = () => apiRequest('/api/orchestration/data'); export const submitOrchestrationTask = (data) => apiRequest('/api/orchestration/task', { method: 'POST', body: JSON.stringify(data) });
第二步:在single-spa生命周期中初始化API
// 子应用 src/singleSpaEntry.js import { createApp } from 'vue'; import App from './App.vue'; import { initApi } from './utils/api'; export async function bootstrap(props) { // 注入容器传递的authService到API单例 initApi(props.authService); } export async function mount(props) { const app = createApp(App); // 可选:将apiRequest挂载到Vue全局,方便组件调用(非强制,不绑定Vue) app.config.globalProperties.$api = apiRequest; app.mount('#sub-app-root'); } export async function unmount(props) { const appEl = document.querySelector('#sub-app-root'); if (appEl) appEl.__vue_app__.unmount(); }
方案优势
- 完全解耦认证逻辑:子应用无需知晓MSAL细节,只依赖封装后的
authService接口,容器统一控制认证规则 - API与Vue无强绑定:API模块是独立的工具类,子应用中的非Vue代码(如工具函数、独立脚本)也能直接调用
- 避免重复初始化:API单例确保整个子应用共用同一认证能力,不会出现重复读取本地存储的问题
- 错误处理统一:容器端封装的
acquireToken已处理静默刷新失败的情况,子应用无需重复编写token刷新逻辑
内容的提问来源于stack exchange,提问作者Joel
相关产品推荐
相关产品推荐

