即使正确的受众在令牌中,Jwt承载令牌受众无效



流程是我有一个本地服务器应用程序"demoServer"它在Azure AD中有相应的应用程序注册。服务器端应用程序是使用ASP编写的。. NET核心WEB API模板。demoServer将从客户端应用程序接收访问令牌,然后对其进行身份验证。目前,我正在为客户端使用本地wpf应用程序。让我们假设wpf应用程序名为demoClient。对于客户端,我也创建了一个应用程序注册。

目前要测试流,我必须遵循以下步骤:1.我得让服务器程序继续运行。2. 我将运行wpf应用程序。它有一个登录按钮。当我点击登录按钮时,我被重定向到微软登录页面。3.我在这里做登录。4. 我得到了访问令牌。5. 令牌被发送到服务器。6. 服务器应该授权令牌并发送响应。

目前一切都很好,直到步骤5。这个问题发生在服务器端得到401错误。我试图在服务器中调用api,也使用swagger,我使用了我在步骤4中获得的访问令牌,并复制和粘贴在swagger授权ui中,我得到了相同的401错误:

www-authenticate: Bearer error="invalid_token",error_description="The audience 'demoServer-applicationId-inAzureAAD' is invalid" 

我尝试解码jwt令牌,aud声明的值为:demoServer-applicationId-inAzureAAD。

那么为什么它显示的值无效?

For mydemoServercs文件包含以下代码:

public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.Configure(app =>
{
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "weatherForecast");
});
if (app.ApplicationServices.GetService<IWebHostEnvironment>().IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
});

webBuilder.ConfigureServices(services =>
{
services.AddControllers();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = "https://login.microsoftonline.com/demoTenantId/v2.0";
options.Audience = "api://demoServer-applicationId-inAzureAAD";

});

services.AddAuthorization(options =>
{
options.DefaultPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
var securityScheme = new OpenApiSecurityScheme
{
Name = "Authorization",
Description = "JWT Authorization header using the Bearer scheme (Example: 'Bearer 12345abcdef')",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
Scheme = "Bearer",
BearerFormat = "JWT",
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
};
c.AddSecurityDefinition("Bearer", securityScheme);
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{ securityScheme, Array.Empty<string>() }
});
});
});
});
}

在demoServer应用注册中,我已经暴露了一个api:api://demoServer-applicationId-inAzureAAD/文件。读

我还在授权的客户端应用程序中添加了demoClient-applicationId-inAzureAAD。

是的,还有文件。读权限已经在demoServer应用注册API权限中添加。

下面的代码是用于wpf应用程序的:

public partial class MainWindow : Window
{

public class TokenProvider
{
private readonly string _clientId;
private readonly string _tenantId;
private readonly string _redirectUri;
public TokenProvider(string clientId, string tenantId, string redirectUri)
{
_clientId = clientId;
_tenantId = tenantId;
_redirectUri = redirectUri;
}
public async Task<string> GetAccessTokenAsync(string[] scopes)
{
IPublicClientApplication app = PublicClientApplicationBuilder
.Create(_clientId)
.WithTenantId(_tenantId)
.WithRedirectUri(_redirectUri)
.Build();
AuthenticationResult result = await app.AcquireTokenInteractive(scopes).ExecuteAsync();
return result.AccessToken;
}
}
private async Task<string> CallApiWithTokenAsync(string accessToken)
{
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
HttpResponseMessage response = await client.GetAsync("https://localhost-Url-For-ServerApp/Demo");
if (response.IsSuccessStatusCode)
{
return await response.Content.ReadAsStringAsync();
}
else
{
throw new Exception($"API call failed with status code {response.StatusCode}");
}
}
}
private async void LoginButton_Click(object sender, RoutedEventArgs e)
{
string[] scopes = new string[] { "api://demoServer-applicationId-inAzureAAD/Files.Read", "api://demoServer-applicationId-inAzureAAD/user_impersonation" };
TokenProvider tokenProvider = new TokenProvider("demoClient-applicationId-inAzureAAD",
"TenantID",
"https://localhost-Url-For-ServerApp");
string accessToken = await tokenProvider.GetAccessTokenAsync(scopes);
Debug.WriteLine(accessToken);
// Send the access token to the server app for authentication.
await CallApiWithTokenAsync (accessToken);
}
public MainWindow()
{
InitializeComponent();
}                           

}

示例标记:

{
"typ": "JWT",
"alg": "RS256",
"kid": "-XXXXXXXXXXXXXXXXXXXX"
}.{
"aud": "demoServer-applicationId-inAzureAAD",
"iss": "https://login.microsoftonline.com/tenantID/v2.0",
"iat": ###########,
"nbf": ###########,
"exp": ###########,
"aio": "######################################",
"azp": "demoClient-applicationId-inAzureAAD",
"azpacr": "0",
"name": "My Name",
"oid": "someID",
"preferred_username": "myEmail",
"rh": "######################.",
"scp": "Demo Files.Read user_impersonation",
"sub": "######################",
"tid": "tenantID",
"uti": "#######################",
"ver": "2.0"
}.[Signature]

你的受众价值是错误的:

options.Audience = "api://demoServer-applicationId-inAzureAAD";

应:

options.Audience = "demoServer-applicationId-inAzureAAD";

最新更新