.NET Core 3.1 API 调用 .NET Framework WCF 服务使用 Windows 身份验证(AD 组)进行保护 [英] .NET Core 3.1 API Calling .NET Framework WCF Service secured using windows authentication (AD Group)

查看:17
本文介绍了.NET Core 3.1 API 调用 .NET Framework WCF 服务使用 Windows 身份验证(AD 组)进行保护的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从 .NET Core 3.1 API 调用 .NET Framework WCF 服务(由使用 AD 组的 Windows 身份验证保护),但是我收到错误消息:

I am trying to call a .NET Framework WCF Service (which is secured by Windows Authentication using an AD group) from a .NET Core 3.1 API however I am getting the error message:

System.ServiceModel.Security.MessageSecurityException:HTTP 请求未经客户端身份验证方案协商"授权.从服务器收到的身份验证标头是协商,NTLM".

System.ServiceModel.Security.MessageSecurityException: The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'Negotiate, NTLM'.

.NET Core API 托管在 Windows 上的 IIS 中,它在其下运行的应用程序池有一个域帐户,该帐户位于访问所需的 AD 组中.我们目前有其他 .NET Framework 应用程序调用 WCF 服务,它们都可以工作,但是这是第一个调用它的 .NET Core 应用程序.部署 API 的服务器和部署 WCF 服务的服务器都存在于支持 Kerberos 协议的同一域中.

The .NET Core API is hosted in IIS both on windows and the app pool that it runs under has a domain account which is in the AD Group required for access. We currently have other .NET Framework applications calling the WCF service and they all work however this is the first .NET Core application to call it. Both servers which the API is deployed to and the WCF service is deployed to exist on the same domain that support Kerberos protocol.

它在本地运行时可以成功运行,但是当部署到服务器上时,它会给出上述错误消息.

It works successfully when running locally however when deployed onto a server it gives the above error message.

来自发生错误消息的 IIS 日志:

IIS Logs from the error message occuring:

POST/Broadcast.svc - 8081 - 172.27.19.200 - - 401 2 5 0
POST/Broadcast.svc - 8081 - 172.27.19.200 - - 401 1 3221225581 0

POST /Broadcast.svc - 8081 - 172.27.19.200 - - 401 2 5 0
POST /Broadcast.svc - 8081 - 172.27.19.200 - - 401 1 3221225581 0

这是 API 中的客户端代理创建代码:

This is the client proxy creation code in the API:

    public IWcfClient<IBroadcastService> CreateBroadcastService()
    {
        var binding = new BasicHttpsBinding(BasicHttpsSecurityMode.Transport);
        binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
        binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.Windows;

        var client = new WcfClient<IBroadcastService>(
            binding,
            new EndpointAddress($"{remoteUrl}/Broadcast.svc"));

        //My expectation is that the below line would make the call send the AppPoolIdentity Credentials?
        client.ClientCredentials.Windows.ClientCredential = CredentialCache.DefaultNetworkCredentials;

        return client;
    }

WcfClient.cs(ClientBase 的包装器):

WcfClient.cs (Wrapper for ClientBase):

public class WcfClient<TChannel> : ClientBase<TChannel>, IWcfClient<TChannel> where TChannel : class
{
    public WcfClient(Binding binding, EndpointAddress endpointAddress)
        : base(binding, endpointAddress)
    { }

    /// <summary>
    /// Executes a given action against <see cref="TChannel" />.
    /// </summary>
    /// <param name="invokeAction">The invocation action.</param>
    public void Invoke(Action<TChannel> invokeAction)
    {
        try
        {
            invokeAction(Channel);
            Close();
        }
        catch (CommunicationException)
        {
            Abort();
            throw;
        }
        catch (TimeoutException)
        {
            Abort();
            throw;
        }
    }

    /// <summary>
    /// Executes the given action against <see cref="TChannel" /> and returns the result.
    /// </summary>
    /// <typeparam name="TResult">The type of the result.</typeparam>
    /// <param name="invokeFunc">The invocation function.</param>
    /// <returns>An instance of <see cref="TResult" /></returns>
    public TResult Invoke<TResult>(Func<TChannel, TResult> invokeFunc)
    {
        TResult result;

        try
        {
            result = invokeFunc(Channel);
            Close();
        }
        catch (CommunicationException)
        {
            Abort();
            throw;
        }
        catch (TimeoutException)
        {
            Abort();
            throw;
        }

        return result;
    }
}

Startup.cs API 配置方法:

Startup.cs Configure method for API:

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        logger.Information("Configuring application middleware...");

        if (env.IsDevelopment())
            app.UseDeveloperExceptionPage();

        app.UseSwaggerMiddleware();

        app.UseSerilogRequestLogging();

        app.UseHttpsRedirection();

        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints => { endpoints.MapControllers(); });

        ConfigCache.SetRootDirectory(Path.Combine(env.ContentRootPath, "App_Data"));

        logger.Information("Application middleware configured successfully.");
    }

API 的 Program.cs:

Program.cs for API:

public class Program
{
    [UsedImplicitly]
    public static void Main(string[] args)
    {
        var appConfig = new ConfigurationBuilder()
            // ReSharper disable once StringLiteralTypo
            .AddJsonFile("appsettings.json")
            .Build();

        Log.Logger = new LoggerConfiguration()
            .ReadFrom.Configuration(appConfig)
            .Enrich.FromLogContext()
            .CreateLogger();

        CreateHostBuilder(args).Build().Run();
    }

    [UsedImplicitly]
    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(
                webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                    webBuilder.UseIIS();
                    webBuilder.UseSerilog();
                });
}

.NET Framework WCF 服务 web.config 的 web.config 具有像这样的指定角色(我已经删除了实际名称)

The web.config for the .NET Framework WCF service web.config has the specified role in like so (I have removed actual name)

<system.web>
    <authentication mode="Windows"/>
    <authorization>
      <allow roles="DOMAINGROUPNAME"/>
      <deny users="*"/>
    </authorization>
</system.web>

谁能告诉我我是否遗漏了什么或提供有关如何缩小问题范围的任何想法?如果您需要查看代码的任何其他区域,也请发表评论,我们很乐意提供它们.

Can anyone tell me if I have missed anything or provide any ideas on how to narrow down the problem? Also please comment if you need to see any other areas of the code and will be happy to supply them.

推荐答案

事实上它们都托管在同一台机器上,您可能需要填充 BackConnectionHostNames 注册表项以禁用环回安全功能.

The fact they are both are hosted on the same machine, you may need to populate the BackConnectionHostNames registry key to disable the loopback security functionality.

这里的步骤:https://stackoverflow.com/a/48086033/4813939

这篇关于.NET Core 3.1 API 调用 .NET Framework WCF 服务使用 Windows 身份验证(AD 组)进行保护的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆