Blazor Server应用中能否将GraphServiceClient注入到Scoped服务中
错误原因分析
你遇到的No account or login hint was passed to the AcquireTokenSilent call报错,核心是自定义的UserService没有获取到当前已认证用户的上下文信息:
- 微软官方的Microsoft Graph集成依赖当前请求的HttpContext中存储的已认证ClaimsPrincipal,来提取用户标识用于静默获取访问令牌
- 你之前继承ComponentBase加
[Authorize]的组件能正常运行,是因为[Authorize]特性会提前完成身份验证流程,将用户身份信息加载到当前请求上下文中,Blazor组件初始化时会自动把上下文传递给注入的GraphServiceClient,所以调用正常 - 你的UserService既没有注入上下文访问能力,同时原来的同步调用逻辑也会导致上下文丢失,GraphServiceClient无法找到对应用户的令牌缓存,因此抛出报错。
解决方案
1. 注册IHttpContextAccessor服务
在Startup.cs的ConfigureServices方法中添加HttpContextAccessor的注册,用于获取当前请求的用户上下文:
public void ConfigureServices(IServiceCollection services) { // 新增这一行 services.AddHttpContextAccessor(); // 保留你原有其他配置不变 var initialScopes = Configuration.GetValue<string>("DownstreamApi:Scopes")?.Split(' '); services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd")) .EnableTokenAcquisitionToCallDownstreamApi(initialScopes) .AddMicrosoftGraph(Configuration.GetSection("DownstreamApi")) .AddInMemoryTokenCaches(); // ... 其他原有服务注册 }
2. 修改自定义UserService逻辑
注入IHttpContextAccessor获取当前用户,将所有Graph相关调用改为异步实现:
public class UserService { private readonly GraphServiceClient _graphClient; private readonly IHttpContextAccessor _httpContextAccessor; private User _cachedUser; public UserService(GraphServiceClient graphClient, IHttpContextAccessor httpContextAccessor) { _graphClient = graphClient; _httpContextAccessor = httpContextAccessor; } public async Task<string> GetUserNameAsync() { var user = await GetCurrentUserAsync(); return user?.DisplayName ?? string.Empty; } private async Task<User> GetCurrentUserAsync() { if (_cachedUser != null) return _cachedUser; // 校验当前请求是否有已认证的用户 var currentPrincipal = _httpContextAccessor.HttpContext?.User; if (currentPrincipal == null || !currentPrincipal.Identity.IsAuthenticated) { return null; } try { _cachedUser = await _graphClient.Me.Request().GetAsync(); return _cachedUser; } catch (Exception ex) { Console.WriteLine($"获取用户信息失败: {ex.Message}"); return null; } } }
3. 正确调用UserService
在Blazor组件中调用时,必须添加[Authorize]特性确保上下文已认证,并且使用异步方式调用方法:
@page "/your-page" @inject UserService UserService @attribute [Authorize] <p>当前登录用户:@_userName</p> @code { private string _userName; protected override async Task OnInitializedAsync() { _userName = await UserService.GetUserNameAsync(); } }
内容的提问来源于stack exchange,提问作者user3893011
相关产品推荐
相关产品推荐

