You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 17:55:15