我已使用 Microsoft Identity 保护我的 .NET 8 Blazor 应用程序。在我的应用程序中,我想从我的 API 获取数据,并且也使用 Microsoft Identity 进行保护。我使用
DownstreamAPI
代表用户发送请求。我按照 Microsoft 的教程来设置我的应用程序。本教程基于 .NET 7,并且运行良好,因此我的设置似乎是正确的。
程序.cs
JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration)
.EnableTokenAcquisitionToCallDownstreamApi(
new string[] {
builder.Configuration.GetSection("DownstreamApi:Scopes:Read").Get<string>()!,
builder.Configuration.GetSection("DownstreamApi:Scopes:Write").Get<string>()!
}
)
.AddDownstreamApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi"))
.AddInMemoryTokenCaches();
builder.Services.AddControllersWithViews()
.AddMicrosoftIdentityUI();
builder.Services.AddAuthorization(options =>
{
// By default, all incoming requests will be authorized according to the default policy
options.FallbackPolicy = options.DefaultPolicy;
});
// Add services to the container.
builder.Services.AddRazorPages();
应用程序设置.json
{
"AzureAd": {
"Authority": "https://login.microsoftonline.com/<DIRECTORY>/",
"ClientId": "<CLIENT_ID>",
"CallbackPath": "/signin-oidc",
"SignedOutCallbackPath ": "/signout-oidc",
"ClientCredentials": [
{
"SourceType": "ClientSecret",
"ClientSecret": "<CLIENT_SECRET>"
}
]
},
"DownstreamApi": {
"Scopes": {
"Read": "api://<CLIENT_ID>/ToDoList.Read",
"Write": "api://<CLIENT_ID>/ToDoList.ReadWrite"
},
"BaseUrl": "https://localhost:7281"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
发送请求
@inject IDownstreamApi DownstreamApi;
...
@code
{
...
private async Task GetFromApi()
{
try
{
Console.WriteLine("Getting token");
var auth = await DownstreamApi.CallApiForUserAsync(
ServiceName,
options => options.RelativePath = "/api/authTest");
Console.WriteLine(auth.StatusCode);
Console.WriteLine(auth.Content.ReadAsStringAsync().Result);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
问题是它发送到 API 的不记名令牌似乎不正确。当我使用 jwt.io 销毁不记名令牌时,结果如下:
.NET 7(工作令牌):
.NET 8(无效令牌)
我似乎无法找出我错过了什么或做错了什么。
就像您提到的那样,该令牌看起来是不正确的令牌。
我有下面的代码来生成 2 个代币,让我们看看差异。
var token = await TokenAcquisitionService.GetAccessTokenForUserAsync(new string[] { "User.Read" });
var token2 = await TokenAcquisitionService.GetAccessTokenForUserAsync(new string[] { "api://client_id/Tiny.Greet" });
我使用
ITokenAcquisition
服务生成我们调用外部 API 所需的访问令牌,该令牌也由 AAD 保护,第一个令牌用于调用 MS Graph API,第二个令牌用于我的自定义 API。
由于您没有分享任何代码来证明您拥有什么样的 Blazor 应用程序,所以我只能分享我所有的相关代码和设置。我使用的是 blazor web 应用程序 .net 8,它是从 blazor 服务器项目 .net 7 转换而来的。您可以查看 这个答案,看看我在迁移中更改了哪些内容。
using BlazorServer7To8.Data;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.UI;
using BlazorServer7To8;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.Extensions.Configuration;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi()
.AddDistributedTokenCaches();
builder.Services.AddControllersWithViews()
.AddMicrosoftIdentityUI();
builder.Services.AddAuthorization(options =>
{
// By default, all incoming requests will be authorized according to the default policy
options.FallbackPolicy = options.DefaultPolicy;
});
builder.Services.AddRazorPages();
//builder.Services.AddServerSideBlazor()
// .AddMicrosoftIdentityConsentHandler();
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents()
.AddMicrosoftIdentityConsentHandler();
builder.Services.AddCascadingAuthenticationState();
builder.Services.AddSingleton<WeatherForecastService>();
在
Index.razor
中,注入ITokenAcquisition
服务来生成访问令牌,因为我们在Program.cs中已经有了EnableTokenAcquisitionToCallDownstreamApi
。
@page "/"
@using Microsoft.Identity.Web
@inject Microsoft.Identity.Web.ITokenAcquisition TokenAcquisitionService
<PageTitle>Index</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
<SurveyPrompt Title="How is Blazor working for you?" />
@code{
protected override async Task OnInitializedAsync()
{
var token = await TokenAcquisitionService.GetAccessTokenForUserAsync(new string[] { "User.Read" });
var token2 = await TokenAcquisitionService.GetAccessTokenForUserAsync(new string[] { "api://client_id/Tiny.Greet" });
var a = 1;
}
}
虽然我使用 Graph API 进行了下游 API 设置,但这并不影响我使用 On_behalf_flow 为其他范围生成另一个访问令牌。
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "tenant_Id",
"TenantId": "tenant_Id",
"ClientId": "client_Id",
"CallbackPath": "/signin-oidc",
"ClientSecret": "client_secret"
},
"DownstreamApi": {
"BaseUrl": "https://graph.microsoft.com/v1.0",
"Scopes": "User.ReadWrite.All"
}
我相信正确的访问令牌可以帮助解决您的错误。这是我对令牌生成的测试结果。