从守护程序应用程序在 Azure 中调用 ASP .NET Core API

Call ASP .NET Core API in Azure from daemon application

我对 Azure AD 和身份验证机制的经验有限。到目前为止,我无法弄清楚为什么不起作用。这是场景:

我在 azure 网络应用服务中部署了一个 ASP net core 2.1 应用程序。 对于身份验证,我使用 Open ID 连接 .AddOpenIdConnect 并提供 client_id, secret_id 等。当用户访问我的网站 API 时,他们将被重定向到 Microsoft 登录。

现在我需要将 API 公开给不在 Azure.

中的第三方应用程序(计划的 Web 作业)

我尝试使用 Microsoft 中的示例,仅使用控制台应用程序,因为我已经在 Azure 中使用了 WebApp。 运行 我能够获取令牌的示例,但是当我调用我的 API 时,响应是 HTML Microsoft 登录页面。

Azure 门户上

Enterprise Application -> daemon-console -> Activity -> Service Principal sign-ins

可以看到登录成功

注意:为了测试我 运行 我在本地机器上的 Web 应用程序和我正在调用 API https://localhost:44306/api/test 的控制台应用程序。

Asp.net 核心应用程序:

services.AddAuthentication(option =>
{
    option.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    option.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    option.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(option =>
{
    option.Cookie.Name = "myWebApp"; 
    option.Cookie.SecurePolicy = CookieSecurePolicy.Always;
    option.Cookie.SameSite = SameSiteMode.None;
})
.AddOpenIdConnect(option =>
{
    option.ClientId = client_id;
    option.ClientSecret = client_secret;
    option.Authority = authority;
    option.SignedOutRedirectUri = "http://localhost:44306/";
    option.CorrelationCookie.Name = "myWebAppCorrelation"; 
    option.CorrelationCookie.SecurePolicy = CookieSecurePolicy.Always;
    option.NonceCookie.Name = "WebAppNonce";
    option.NonceCookie.SecurePolicy = CookieSecurePolicy.Always;
    option.Resource = "https://graph.windows.net";
    option.ResponseType = "id_token code";
})

控制台应用试图访问 API(从 Microsoft 示例中提取的代码)

app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
    .WithClientSecret(config.ClientSecret)
    .WithAuthority(new Uri(config.Authority))
    .Build();
    
result = await app.AcquireTokenForClient(scopes).ExecuteAsync(); // ok

var httpClient = new HttpClient();
var defaultRequestHeaders = httpClient.DefaultRequestHeaders;
if (defaultRequestHeaders.Accept == null || !defaultRequestHeaders.Accept.Any(m => m.MediaType == "application/json"))
{
    httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
defaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);

HttpResponseMessage response = await httpClient.GetAsync(webApiUrl);
if (response.IsSuccessStatusCode) // ok 
{
    string json = await response.Content.ReadAsStringAsync(); // here I'm getting the HTML to login page
    var result = JsonConvert.DeserializeObject<List<JObject>>(json);
    Console.ForegroundColor = ConsoleColor.Gray;
    processResult(result);
}

示例代码和我的场景之间的唯一区别是示例中的 Web 应用程序使用 services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApi(Configuration) 但我不能在 Asp .Net core 2.1

中使用 .AddMicrosoftIdentityWebApi

有人知道问题出在哪里吗?我需要添加另一个身份验证方案吗?

除了cookie认证,您还需要支持JWT认证。所以你需要加上AddJwtBearer。您还需要扩展身份验证检查,因为您现在支持多种方案。

我会这样做:

// public void ConfigureServices(IServiceCollection services)
services.AddAuthentication(option =>
{
    option.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    option.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    option.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, cfg => {
    cfg.Authority = authority;
    cfg.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
    {
        ValidAudience = /*see scopes of your deamon app*/
    };
})
.AddCookie(option =>
{
    // ...
})
.AddOpenIdConnect(option =>
{
    // ...
})


// public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

app.UseAuthentication();
// https://github.com/aspnet/Security/issues/1847
app.Use(async (context, next) =>
{
    if (!context.User.Identity.IsAuthenticated)
    {
        var result = await context.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);
        if (result.Succeeded)
        {
            context.User = result.Principal;
        }
    }
    await next();
});
app.UseAuthorization();