.Net Core - 使用 AzureAD/EntraID 身份验证访问 Azure DevOps REST API

问题描述 投票:0回答:1

我有一个托管的 Blazor WebAssembly 应用程序,我正在尝试从 Azure DevOps 提取数据。我们目前使用 PAT 进行访问,但我希望人们改用他们的 Entra ID 帐户。

我已按照此处的步骤使用 Entra ID 设置身份验证,因此我可以登录

https://learn.microsoft.com/en-us/aspnet/core/blazor/security/web assembly/hosted-with-microsoft-entra-id?view=aspnetcore-7.0

我目前无法获取有效的访问令牌来调用 Azure DevOps 并检索一些数据。

我不断得到

StatusCode: 203, ReasonPhrase: 'Non-Authoritative Information'

如果是 401,我会认为我的应用程序配置有问题。然而,它是 203,所以我怀疑令牌格式可能不正确。返回的令牌是 JWT 格式,而不是通常的 PAT 格式,所以我不确定如何继续。

下面是我的客户端应用程序代码

程序.cs

using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using testauthblazor.Client;
using testauthblazor.Client.Services;

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");

builder.Services.AddHttpClient("testauthblazor.ServerAPI", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
    .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();

// Supply HttpClient instances that include access tokens when making requests to the server project
builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("testauthblazor.ServerAPI"));
builder.Services.AddScoped<AzureDevOpsService>();

builder.Services.AddMsalAuthentication(options =>
{
    builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
    options.ProviderOptions.DefaultAccessTokenScopes.Add("https://twonline.onmicrosoft.com/xxxx-xxxx-xxxx-xxxx-xxxxxxx/.default");
});
await builder.Build().RunAsync();

测试页.razor

@page "/testpage"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using testauthblazor.Client.Services
@inject AzureDevOpsService DevOpsService
@inject IAccessTokenProvider TokenProvider

<h3>Azure DevOps Projects</h3>

@if (projects == null)
{
    <p>Loading...</p>
}
else if (projects.Count == 0)
{
    <p>No projects found.</p>
}
else
{
    <ul>
        @foreach (var project in projects)
        {
            <li>@project</li>
        }
    </ul>
}

@code {
    private List<string> projects;

    protected override async Task OnInitializedAsync()
    {
        var result = await TokenProvider.RequestAccessToken();
        if (result.TryGetToken(out var token))
        {
            projects = await DevOpsService.GetProjectsAsync(token.Value);
        }
    }
}

AzureDevOpsService.cs

public class AzureDevOpsService(HttpClient httpClient)
{
    private readonly HttpClient _httpClient = httpClient;

    public async Task<List<string>> GetProjectsAsync(string accessToken)
    {
        var request = new HttpRequestMessage(HttpMethod.Get, "https://dev.azure.com/wtwcrb/_apis/projects?api-version=7.1");
        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

        var response = await _httpClient.SendAsync(request);
        response.EnsureSuccessStatusCode();

        var content = await response.Content.ReadAsStringAsync();
        var projects = JsonDocument.Parse(content).RootElement.GetProperty("value").EnumerateArray()
            .Select(p => p.GetProperty("name").GetString()).ToList();

        return projects;
    }
}
c# azure-devops azure-active-directory blazor-webassembly microsoft-entra-id
1个回答
0
投票

发生错误是因为您在生成访问令牌时使用了错误的范围。验证 Azure DevOps API 的正确范围是

499b84ac-1321-427f-aa17-267ca6975798/.default

确保在您的客户端应用程序中添加

vso.project
DevOps API 权限并征得同意,如下所示:

enter image description here

现在更改客户端应用程序的 Program.cs 文件中的以下代码行:

builder.Services.AddMsalAuthentication(options =>
{
    builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
    options.ProviderOptions.DefaultAccessTokenScopes.Add("499b84ac-1321-427f-aa17-267ca6975798/vso.project");
});

当我更改范围值后再次运行项目时,我成功获得了 Azure DevOps 项目列表,如下所示:

enter image description here

参考:

203 使用不记名令牌列出 Azure DevOps 中的 pat 令牌的非权威信息 - 堆栈内存溢出

© www.soinside.com 2019 - 2024. All rights reserved.