我正在尝试从.NET Core 3.1 API调用.NET Framework WCF服务(由Windows身份验证使用AD组保护,但是我收到错误消息:
System.ServiceModel.Security.MessageSecurityException:使用客户端身份验证方案'Negotiate'的HTTP请求是未经授权的。从服务器收到的身份验证标头是“协商,NTLM”。
。NET Core API都托管在Windows上的IIS中,并且它在其下运行的应用程序池具有域帐户,该帐户在访问所需的AD组中。当前,我们还有其他的调用WCF服务的.NET Framework应用程序,它们都可以工作,但这是第一个调用它的.NET Core应用程序。部署API的服务器和部署WCF服务的两个服务器都存在于支持Kerberos协议的同一域中。
它在本地运行时可以成功工作,但是当部署到服务器上时,它会显示上述错误消息。
发生错误消息的IIS日志:
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中的客户端代理创建代码:
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的包装):
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的配置方法:
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:
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具有指定的角色,就像这样(我已经删除了实际名称)
<system.web>
<authentication mode="Windows"/>
<authorization>
<allow roles="DOMAIN\GROUPNAME"/>
<deny users="*"/>
</authorization>
</system.web>
有人可以告诉我我是否有任何遗漏或提供任何想法来缩小问题的范围吗?另外,如果您需要查看代码的任何其他区域,也请发表评论,并乐意提供它们。
事实上它们都托管在同一台计算机上,您可能需要填充BackConnectionHostNames注册表项以禁用回送安全功能。
我看到您使用Windows身份验证。使用Windows身份验证时,该服务器也应该存在于使用Kerberos协议作为其域控制器的Windows域中。如果服务器不在Kerberos支持的域上,或者Kerberos系统失败,则可以使用NT LAN Manager。