繁体   English   中英

同一应用程序上的 AAD OpenId 和承载身份验证

[英]AAD OpenId and Bearer Authentication on the same Application

我正在尝试使用 Azure Active Directory 身份验证创建身份验证,我的应用程序由 WebApis 和 WEb 页面组成,如果用户请求应用程序“控制器”页面,我想要实现的是将用户重定向到 Microsoft 登录页面,并在通过令牌调用 API controller 时授权客户端应用程序。

我设法通过如下设置 Startup.Auth.cs 来做到这一点

public void ConfigureAuth(IAppBuilder app)
    {
        app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

        app.UseCookieAuthentication(new CookieAuthenticationOptions());
        app.UseOpenIdConnectAuthentication(
        new OpenIdConnectAuthenticationOptions
        {
            
            ClientId = clientId,
            Authority = authority,
            RedirectUri = redirectUri,
            PostLogoutRedirectUri = redirectUri,
            Scope = OpenIdConnectScope.OpenIdProfile,
            ResponseType = OpenIdConnectResponseType.IdToken,
            TokenValidationParameters = new TokenValidationParameters()
            {
                ValidateIssuer = true
            },
            Notifications = new OpenIdConnectAuthenticationNotifications
            {
                AuthenticationFailed = OnAuthenticationFailed
            }
        });

                    app.UseWindowsAzureActiveDirectoryBearerAuthentication(
               new WindowsAzureActiveDirectoryBearerAuthenticationOptions
               {
                   Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
                   TokenValidationParameters = new TokenValidationParameters { SaveSigninToken = true, ValidAudience = $"api://{clientId}" }
               });
    }

用 [Authorize] 属性装饰我的控制器

但是,当未经授权的客户端应用程序调用 API 时,它会返回以下内容

  <html>

<head>
    <title>Working...</title>
</head>

<body>
    <form method="POST" name="hiddenform" action="https://local:44341/">
        <input type="hidden" name="id_token" value="eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Im5PbzNaRHJPRFhFSzFqS1doWHNsSFJfS1hFZyJ9.eyJhdWQiOiI3NjIzMjcyMC1hNmViLTRkOTctOTI3Yy1lMWFjNzRiODIyMjAiLCJpc3MiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vYjFmZTVlMmEtZjc1Yy00NDQxLTlmYjItNWFjYzAxYmEwMGQwL3YyLjAiLCJpYXQiOjE2MTA3MzAJub25jZSI6IjYzNzQ2MzI3OTEwNDAxMzk3Ni5aR0k1TmpCaU1XWXRPRGsxT0MwMFpEWmlMV0kxWXprdE9ESTFZMlZrTWpjeU0yWTJNRFZqTWpnNU9EY3RNak0yWkMwME1qWmpMV0UwTTJZdE5XSXpNVFZsTlRKa1pHRXgiLCJvaWQiOiJiN2YzMjg1Mi1hMDRhLTRlOWUtYjFjOS02NTI5NDk3YTgyZDEiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiIyMjQxN0Byai5jb20iLCJyaCI6IjAuQUFBQUtsNy1zVnozUVVWoeHm6x2ad02ExHlw48lfRVZhEoHw8cZ5SWRFOGZfi3TJ3aOFKdaDZZ8Yt1no30Hku8pL3Vf7Lrq-BuKX8PNtkU45aVO1fZf8PFdM4UbpYnHOwvuG1NlPG8mTa1KheQTza9j3PTaiLq8e15jtSoFoHfIJbMZJoNTfvAF40kt9XvYee-rga80Oj1tJX78g_80MmRYORwArr1rq1n6EyPgFHaDDF5vD-zWOLDrXKyj2rwW-7LLpbtojtbsyCPdM5QPkLKnZZFanpvwRAFRTHaLdHINGAlHhvhFP9kvRhVtaTUgwYzrFqlN8k3zSZrvnMOec7A" /><input type="hidden" name="state" value="OpenIdConnect.AuthenticationProperties=7_QsmCbQZ3vBxo1tTvZXcYRLeNQMBZfanq5zpZvqNjuudSAu52-UZnVGkkWMXeBh_rIHE3i_j8g_B751WFqQHR1CXJrdjBi6PZy-" /><input type="hidden" name="session_state" value="5938bc609" /><noscript>
            <p>Script is disabled. Click Submit to continue.</p><input type="submit" value="Submit" /></noscript></form>
    <script language="javascript">
        document.forms[0].submit();
    </script>
</body>

</html>

但是当从我的 function 中删除 UseOpenIdConnectAuthentication 调用时,它返回了正确的响应消息,状态码为 401

{    "Message": "Authorization has been denied for this request."}

话虽如此,任何人都可以帮助我了解如何为 web api 和 web 应用程序页面的 openIdConnect 设置不记名令牌身份验证。

谢谢,请告诉我我的方法是否错误,并根据我的要求推荐正确的方法。

不要在此处使用 UseOpenIdConnectAuthentication,它用于自定义 OpenID 支持,这在此处并不真正适用,使用开箱即用的 Azure AD 特定助手,如您接下来使用的助手。

这是服务器端的一个很好的起点: https://docs.microsoft.com/en-us/azure/active-directory/develop/scenario-protected-web-api-overview

对于客户端,通用调用者(控制台应用程序或任意服务): https://docs.microsoft.com/en-us/azure/active-directory/develop/scenario-daemon-overview

对于客户端,需要保护自身的交互式 web 应用程序: https://docs.microsoft.com/en-us/azure/active-directory/develop/scenario-web-app-sign-user-overview

简而言之,您的 API 客户端必须向 Azure AD 询问令牌以访问您的 API 端点。 要让 Azure AD 知道此令牌用于哪个资源,请为您的 API 创建一个应用程序注册,并使用其客户端 ID 和任何其他必要参数配置 API 应用程序。

当您的应用程序收到令牌时,它必须联系 Azure AD 进行验证。 对于此调用,它应该使用您在 Azure AD 中为其生成的客户端 ID。

您可能希望在模拟真实 AD 登录时运行客户端,或者您可能将客户端作为某个 AD 主体(应用程序注册)运行。 看看下面的 .NET Core 3.1 客户端应用程序示例是否可以让您继续前进。 它使用其 id 和秘密模拟一些 AD 主体,因此它可以从 Azure 云外部运行并连接到 Azure AD 保护的服务,而无需托管身份。

要使下面的示例正常工作,请确保正确配置客户端应用程序和服务器 API 的主体(应用程序注册/企业应用程序)。 这是一个相当独立的话题,在上面链接的官方文档中有很好的描述。

如果您的客户端作为 Azure AppService 或在 Azure VM 上运行,则最好使用 Azure 托管标识。 这消除了对机密的需求并简化了对 AzureServiceTokenProvider 的构造函数调用(无参数 = 使用环境上下文 = 获取托管标识)。 不幸的是,通过 Azure 进行本地开发并不容易。

using Microsoft.Azure.Services.AppAuthentication;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace N
{
    public class Test
    {
        public async Task Main(IConfigurationRoot config, ILoggerFactory loggerFactory)
        {
            using var httpClient = new HttpClient(new HttpClientHandler
            {
                ServerCertificateCustomValidationCallback = (msg, cert, chain, errors) =>
                {
                    return true;
                }
            });

            var url = "https://localhost:5000";
            var clientId = "guid of your caller's identity App Registration";
            var clientSecret = "secret you produced for your caller's managed identity App Registration";
            var tenantId = "guid (Azure tenant id)";
            var runAs = $"RunAs=App;AppId={clientId};TenantId={tenantId};AppKey={clientSecret}";

            var tokenProvider = new AzureServiceTokenProvider(runAs);
            var accessToken = await tokenProvider.GetAccessTokenAsync("https://my-test-app-identity.azurewebsites.net");

            var requestMessage = new HttpRequestMessage(HttpMethod.Get, new Uri(uri));
            requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

            var response = await httpClient.SendAsync(requestMessage);
            response.EnsureSuccessStatusCode();
            var content = await response.Content.ReadAsStringAsync();

            foreach (var header in response.Headers)
            {
                Console.WriteLine(header.Key + ": " + string.Join(",", header.Value));
            }
            Console.WriteLine(content);
        }
    }
}

.csproj 中的依赖:

<PackageReference Include="Azure.Core" Version="1.4.1" />
<PackageReference Include="Azure.Identity" Version="1.2.2" />
<PackageReference Include="Azure.Security.KeyVault.Keys" Version="4.1.0" />
<PackageReference Include="Azure.Security.KeyVault.Secrets" Version="4.1.0" />
<PackageReference Include="Microsoft.Identity.Client" Version="4.17.1" />

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM