React中使用Azure B2C调用Graph SDK获取用户信息遇令牌验证错误
问题分析与解决方案
问题1:自定义Scope导致受众无效
你用的https://my-tanent.onmicrosoft.com/my-app/user.read是针对自身应用的API权限Scope,不是Microsoft Graph的官方Scope。用这个Scope获取的令牌,受众(aud)是你的客户端ID,而Graph API要求令牌的aud必须是https://graph.microsoft.com,自然会触发“无效受众”的错误。
问题2:使用.defaultScope返回空令牌
https://graph.microsoft.com/.default是一种静态Scope,需要满足两个前提:
- 你的B2C应用已正确添加Microsoft Graph的委派权限(比如
User.Read); - 已对该权限授予管理员同意(B2C租户的管理员同意需要用全局管理员账号操作)。
另外,登录请求(loginRequest)中必须包含Graph相关的Scope,否则MSAL不会缓存对应的访问令牌,导致acquireTokenSilent无法获取到令牌,返回空值。
修正步骤
确认权限配置
- 登录Azure门户,找到你的B2C应用,进入「API权限」页面;
- 添加Microsoft Graph的委派权限(比如
User.Read); - 点击「授予管理员同意」,完成权限授权。
修正代码中的Scope
调用Graph API必须使用Microsoft Graph的官方Scope,可直接简写为User.Read(MSAL会自动补全前缀https://graph.microsoft.com/),同时确保登录请求中也包含该Scope。修正后的完整代码
import React from 'react'; import { AuthenticatedTemplate, UnauthenticatedTemplate, useMsal, } from '@azure/msal-react'; import { loginRequest } from '../authConfig'; import { InteractionRequiredAuthError } from '@azure/msal-browser'; import { AuthCodeMSALBrowserAuthenticationProvider } from '@microsoft/microsoft-graph-client/authProviders/authCodeMsalBrowser'; import { InteractionType } from '@azure/msal-browser'; import { Client } from '@microsoft/microsoft-graph-client'; const Home = () => { const { instance } = useMsal(); const { accounts } = useMsal(); let graphClient = undefined; // 使用Microsoft Graph的官方Scope const scopes = [ 'openid', 'offline_access', 'User.Read' ]; const authProvider = new AuthCodeMSALBrowserAuthenticationProvider(instance, { account: accounts[0], scopes, interactionType: InteractionType.Popup, }); function ensureClient() { graphClient = Client.initWithMiddleware({ authProvider: authProvider, }); return graphClient; } async function getUser() { try { ensureClient(); const user = await graphClient .api('/me') .select('displayName,mail,mailboxSettings,userPrincipalName') .get(); console.log(user); } catch (error) { console.error('获取用户信息失败:', error); } } const getAccessToken = async () => { try { // 明确指定账户,避免多账户场景下的问题 const token = await instance.acquireTokenSilent({ scopes, account: accounts[0] }); console.log('获取到的令牌:', token); } catch (error) { // 静默获取失败时,弹出窗口请求令牌 if (error instanceof InteractionRequiredAuthError) { const token = await instance.acquireTokenPopup({ scopes }); console.log('弹窗获取到的令牌:', token); } else { console.error('获取令牌失败:', error); } } }; return ( <> <UnauthenticatedTemplate> <h3 className="h3">Login</h3> <button onClick={() => instance.loginPopup(loginRequest)}>Login</button> </UnauthenticatedTemplate> <AuthenticatedTemplate> <div className="App"> <header className="App-header"> <p>Hello {accounts[0]?.name}!</p> <button onClick={() => instance.logoutRedirect({ postLogoutRedirectUri: '/' })}>Logout</button> <button onClick={() => getUser()}>Get User</button> <button onClick={() => getAccessToken()}>AcquireTokenSilent</button> </header> </div> </AuthenticatedTemplate> </> ); };
- 修正authConfig中的loginRequest
确保登录请求包含Graph的Scope:
// authConfig.js export const loginRequest = { scopes: ['openid', 'offline_access', 'User.Read'] };
额外注意事项
- 验证令牌的
aud字段是否为https://graph.microsoft.com,只有这样的令牌才能被Graph API接受; - 如果仍出现空令牌问题,清除浏览器缓存后重新登录,确保MSAL缓存了正确的访问令牌。
内容的提问来源于stack exchange,提问作者Mohmad sabban
相关产品推荐
相关产品推荐

