如何修复调用 GetAccessTokenForAppAsync 以获取导致 NullReferenceException 的令牌?
How to fix calling GetAccessTokenForAppAsync to acquire token resulting in a NullReferenceException?
我正在研究如何在 ASP.NET Core 3.1 Razor Pages 应用程序中使用 Microsoft Graph API。我找到了 this 指南并使其大部分工作(以及检索令牌),直到我意识到我需要在没有用户的情况下访问 API。
目前,我卡住了,因为我无法使用 ITokenAcquisition
GetAccessTokenForAppAsync
方法检索令牌。它一直导致 NullReferenceException
。不知道是我的启动设置有问题还是怎么的,就是想不通。
System.NullReferenceException: 'Object reference not set to an instance of an object.'
我知道 Get access without a user 指南,我理解并可以开始工作,但我特别想使用 GetAccessTokenForAppAsync
方法,因为它会为我管理刷新令牌。否则,我将不得不在每次 API 调用时继续查询新令牌,并且不断生成有效令牌似乎是个坏主意。
Startup.cs ConfigureServices 方法:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddHttpClient();
services.AddMicrosoftIdentityWebApiAuthentication(Configuration)
.EnableTokenAcquisitionToCallDownstreamApi()
// Use in-memory token cache
// See https://github.com/AzureAD/microsoft-identity-web/wiki/token-cache-serialization
.AddInMemoryTokenCaches();
...
}
Index.cshtml.cs。这是我打电话获取令牌的地方:
public class IndexModel : PageModel
{
private readonly IHttpClientFactory _clientFactory;
private readonly ITokenAcquisition _tokenAcquisition;
public IndexModel(IHttpClientFactory clientFactory, ITokenAcquisition tokenAcquisition)
{
_clientFactory = clientFactory;
_tokenAcquisition = tokenAcquisition;
}
public async Task OnGet()
{
// results in NullReferenceException
string token = await _tokenAcquisition.GetAccessTokenForAppAsync("https://graph.microsoft.com/.default", tenant:"tenantId");
}
}
appSettings.json。这些值由用户机密 json.
填充
{
"AzureAd": {
"Instance": "",
"ClientId": "",
"TenantId": "",
"CallbackPath": "",
"ClientSecret": "",
"TimeoutInMinutes": ""
},
"ConnectionStrings": {
"DefaultConnection": ""
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
首先,我已经成功重现了您的问题,如下所示:
你得到这个是因为 private readonly ITokenAcquisition _tokenAcquisition;
Note: This is actually a service which helps you to aquire access token on behalf of application. You cannot consume this service as constructor variable.
解法:
您应该按以下方式使用 ITokenAcquisition
服务:
public async Task OnGet()
{
var _tokenAcquisition = this.HttpContext.RequestServices
.GetRequiredService<ITokenAcquisition>() as ITokenAcquisition;
string token = await _tokenAcquisition.GetAccessTokenForAppAsync("https://graph.microsoft.com/.default", tenant: "tenantId");
}
配置在Startup.cs
下
public void ConfigureServices(IServiceCollection services)
{
string[] initialScopes = Configuration.GetValue<string>("DownstreamApi:Scopes")?.Split(' ');
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
.AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
.AddInMemoryTokenCaches();
services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
services.AddRazorPages()
.AddMicrosoftIdentityUI();
}
DownstreamApi 在appsettings.json下:
"DownstreamApi": {
"BaseUrl": "https://graph.microsoft.com/v1.0",
"Scopes": "https://graph.microsoft.com/.default"
}
输出:
希望它能相应地解决您的问题。
我正在研究如何在 ASP.NET Core 3.1 Razor Pages 应用程序中使用 Microsoft Graph API。我找到了 this 指南并使其大部分工作(以及检索令牌),直到我意识到我需要在没有用户的情况下访问 API。
目前,我卡住了,因为我无法使用 ITokenAcquisition
GetAccessTokenForAppAsync
方法检索令牌。它一直导致 NullReferenceException
。不知道是我的启动设置有问题还是怎么的,就是想不通。
System.NullReferenceException: 'Object reference not set to an instance of an object.'
我知道 Get access without a user 指南,我理解并可以开始工作,但我特别想使用 GetAccessTokenForAppAsync
方法,因为它会为我管理刷新令牌。否则,我将不得不在每次 API 调用时继续查询新令牌,并且不断生成有效令牌似乎是个坏主意。
Startup.cs ConfigureServices 方法:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddHttpClient();
services.AddMicrosoftIdentityWebApiAuthentication(Configuration)
.EnableTokenAcquisitionToCallDownstreamApi()
// Use in-memory token cache
// See https://github.com/AzureAD/microsoft-identity-web/wiki/token-cache-serialization
.AddInMemoryTokenCaches();
...
}
Index.cshtml.cs。这是我打电话获取令牌的地方:
public class IndexModel : PageModel
{
private readonly IHttpClientFactory _clientFactory;
private readonly ITokenAcquisition _tokenAcquisition;
public IndexModel(IHttpClientFactory clientFactory, ITokenAcquisition tokenAcquisition)
{
_clientFactory = clientFactory;
_tokenAcquisition = tokenAcquisition;
}
public async Task OnGet()
{
// results in NullReferenceException
string token = await _tokenAcquisition.GetAccessTokenForAppAsync("https://graph.microsoft.com/.default", tenant:"tenantId");
}
}
appSettings.json。这些值由用户机密 json.
填充{
"AzureAd": {
"Instance": "",
"ClientId": "",
"TenantId": "",
"CallbackPath": "",
"ClientSecret": "",
"TimeoutInMinutes": ""
},
"ConnectionStrings": {
"DefaultConnection": ""
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
首先,我已经成功重现了您的问题,如下所示:
你得到这个是因为 private readonly ITokenAcquisition _tokenAcquisition;
Note: This is actually a service which helps you to aquire access token on behalf of application. You cannot consume this service as constructor variable.
解法:
您应该按以下方式使用 ITokenAcquisition
服务:
public async Task OnGet()
{
var _tokenAcquisition = this.HttpContext.RequestServices
.GetRequiredService<ITokenAcquisition>() as ITokenAcquisition;
string token = await _tokenAcquisition.GetAccessTokenForAppAsync("https://graph.microsoft.com/.default", tenant: "tenantId");
}
配置在Startup.cs
下public void ConfigureServices(IServiceCollection services)
{
string[] initialScopes = Configuration.GetValue<string>("DownstreamApi:Scopes")?.Split(' ');
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
.AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
.AddInMemoryTokenCaches();
services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
services.AddRazorPages()
.AddMicrosoftIdentityUI();
}
DownstreamApi 在appsettings.json下:
"DownstreamApi": {
"BaseUrl": "https://graph.microsoft.com/v1.0",
"Scopes": "https://graph.microsoft.com/.default"
}
输出:
希望它能相应地解决您的问题。