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

Next.js App Router集成MSAL登录报错及配置结构咨询

Next.js App Router 集成 MSAL 完整解决方案(解决createContext及Stub实例错误)

一、正确的项目结构

App Router 下需区分服务器组件与客户端组件,MSAL 相关逻辑必须隔离在客户端组件中,调整后的结构如下:

- app
  - layout.tsx(根服务器组件,无需修改为客户端)
  - providers.tsx(客户端组件,封装MsalProvider)
  - page.tsx(可作为服务器组件,仅渲染客户端Auth组件)
  - components
    - AuthButtons.tsx(客户端组件,处理登录/登出逻辑)
- config
  - msal.ts(MSAL配置文件,仅导出配置对象)

二、msal.ts 配置文件的正确写法与位置

配置文件保留在config/msal.ts即可,但禁止在该文件中直接初始化PublicClientApplication(避免服务器端执行报错),仅导出配置对象:

// config/msal.ts
import { Configuration } from '@azure/msal-browser';

export const msalConfig: Configuration = {
  auth: {
    clientId: '你的客户端ID',
    authority: 'https://login.microsoftonline.com/你的租户ID',
    redirectUri: '/', // 按需设置回调地址
  },
  cache: {
    cacheLocation: 'sessionStorage',
    storeAuthStateInCookie: false,
  },
};

三、错误1:createContext only works in Client Components 解决方法

原因

MsalProvider依赖React Context,而App Router默认所有组件为服务器组件,服务器组件无法使用Context、useState等客户端API。

解决步骤

  1. 创建客户端组件app/providers.tsx,顶部添加'use client'指令,在这里初始化MSAL实例并包裹MsalProvider:
// app/providers.tsx
'use client';

import { MsalProvider } from '@azure/msal-react';
import { PublicClientApplication } from '@azure/msal-browser';
import { msalConfig } from '@/config/msal';

// 仅在客户端环境初始化MSAL实例
const pca = new PublicClientApplication(msalConfig);

export function MsalAuthProvider({ children }: { children: React.ReactNode }) {
  return <MsalProvider instance={pca}>{children}</MsalProvider>;
}
  1. 在根layout.tsx中引入该客户端组件,根布局保持为服务器组件即可:
// app/layout.tsx
import { MsalAuthProvider } from './providers';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="zh-CN">
      <body>
        <MsalAuthProvider>{children}</MsalAuthProvider>
      </body>
    </html>
  );
}

四、错误2:BrowserConfigurationAuthError: stubbed_public_client_application_called 解决方法

原因

在服务器环境中初始化了PublicClientApplication(比如原_app.tsx为服务器组件,或在服务器组件中导入了MSAL实例代码),MSAL在服务器端会返回一个Stub空实例,调用它就会触发该错误。

解决步骤

  1. 所有涉及MSAL实例调用、MSAL钩子(useMsal/useIsAuthenticated等)的代码,必须放在添加了'use client'指令的客户端组件中。
  2. 将登录/登出逻辑封装到独立客户端组件app/components/AuthButtons.tsx:
// app/components/AuthButtons.tsx
'use client';

import { useMsal } from '@azure/msal-react';
import { LoginPopupRequest, LogoutRequest } from '@azure/msal-browser';

const loginRequest: LoginPopupRequest = {
  scopes: ['user.read'], // 按需设置权限
};

const logoutRequest: LogoutRequest = {
  postLogoutRedirectUri: '/',
};

export function AuthButtons() {
  const { instance, accounts } = useMsal();

  const handleLogin = () => {
    instance.loginPopup(loginRequest).catch(err => console.error(err));
  };

  const handleLogout = () => {
    instance.logoutRedirect(logoutRequest);
  };

  return (
    <div>
      {accounts.length === 0 ? (
        <button onClick={handleLogin}>登录</button>
      ) : (
        <button onClick={handleLogout}>登出</button>
      )}
    </div>
  );
}
  1. 在page.tsx中导入该组件,page.tsx可保持为服务器组件:
// app/page.tsx
import { AuthButtons } from './components/AuthButtons';

export default function HomePage() {
  return (
    <div>
      <h1>首页</h1>
      <AuthButtons />
    </div>
  );
}

五、关键注意事项

  • 禁止在服务器组件中导入@azure/msal-browser或直接创建PublicClientApplication实例。
  • 所有需要使用MSAL钩子的组件,必须添加'use client'指令。
  • 根布局通过客户端Provider包裹整个应用,确保所有客户端组件能访问MSAL Context。

内容的提问来源于stack exchange,提问作者Snooper_A

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 07:45:07