HTTP请求未经客户端身份验证方案“Ntlm”授权。从服务器接收到的身份验证标头为“Negotiate,NTLM”。

21

我已经查看了大量的SO文章,甚至其他网站,但似乎无法使此服务正常工作。 我有一个SOAP服务我想要访问,它配置如下:

<system.serviceModel>
    <bindings>
        <basicHttpBinding>
        <binding name="PROVIDERSSoapBinding">
            <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Ntlm" proxyCredentialType="None" realm="" />
            </security>
        </binding>
        </basicHttpBinding>
    </bindings>
    <client>
        <endpoint address="http://xxx.xx.xx.xxx:9011/provider/services/PROVIDERS"
            binding="basicHttpBinding" bindingConfiguration="PROVIDERSSoapBinding"
            contract="ServiceReference1.ProviderRemote" name="PROVIDERS" />
    </client>
</system.serviceModel>

然而,当我从我的控制台应用程序中访问时,遇到以下错误:

HTTP请求未经授权,客户端验证方案为“Ntlm”。从服务器接收到的身份验证标头为“Negotiate,NTLM”。

有人能帮我解决吗?


2
你尝试过使用不同的凭证类型来确保它是否能正常工作吗? - iMortalitySX
1
也许首先尝试将“安全模式”设置为“无”,以确保在第一次使用时它可以在没有安全性的情况下工作,然后逐渐提高安全设置。 - Chamila Chulatunga
你使用的是什么环境?(IIS、自托管等) - iMortalitySX
1
客户端和服务是否位于同一台机器上?如果是,则可以参考以下链接:http://support.microsoft.com/kb/896861。 - David Martin
@iMortalitySX,我正在内部网络上访问服务器。因此,该服务已在该服务器上设置好。 - Mike Perrenoud
显示剩余3条评论
8个回答

12

尝试将'clientCredentialType'设置为'Windows'而不是'Ntlm'。

我认为这是服务器所期望的 - 也就是说,当它说服务器期望"Negotiate,NTLM"时,实际上意味着Windows身份验证,它将尝试使用Kerberos(如果可用),或者在不可用时回退到NTLM(因此有"negotiate")

我基于阅读:选择凭据类型

的线索得出这个结论。


7
使用wftech可以消除客户端的问题,这是一个旧工具,但我发现在诊断身份验证问题方面很有用。wfetch允许您指定NTLM、Negotiate和Kerberos,这可能会帮助您更好地了解您的问题。由于您正在尝试调用服务,而wfetch对WCF一无所知,因此建议将终结点绑定(PROVIDERSSoapBinding)应用到serviceMetadata,然后使用相同的安全设置对该服务进行HTTP GET以获取WSDL。
另一个选项是强制服务器使用NTLM,您可以通过编辑元数据(IIS 6)并删除Negotiate设置来实现,更多详细信息请参见http://support.microsoft.com/kb/215383
如果您正在使用IIS 7.x,则方法略有不同,如何配置身份验证提供程序的详细信息在此处http://www.iis.net/configreference/system.webserver/security/authentication/windowsauthentication
我注意到您已经用xxx.xx.xx.xxx屏蔽了服务器地址,因此我猜这是一个IP地址而不是服务器名称,这可能会导致身份验证问题,因此如果可能,请尝试针对机器名称。
很抱歉我没有给出答案,而是提供了更接近问题的指针,但我希望它有所帮助。
最后,我要说我也遇到了同样的问题,我的唯一补救措施是使用Kerberos而不是NTLM,不要忘记如果您选择这条路线,您需要为服务注册SPN。

6
如果您的客户端和服务端都安装在同一台机器上,并且您使用正确的(即已在其他地方经过尝试和测试的)客户端和服务端配置仍然遇到问题,则可能值得检查一下以下内容。
检查主机条目是否存在于您的hosts文件中。

%windir%/system32/drivers/etc/hosts

检查是否使用主机名访问 web 服务,并且该主机名已与上述 hosts 文件中的 IP 地址相关联。 如果是,则不会将 NTLM / Windows 凭据从客户端传递到服务,因为针对该主机名的任何请求都将在机器级别再次路由。
请尝试以下任一选项:
  • 从hosts文件中删除该主机条目。
  • 如果无法删除主机条目,则尝试使用另一个主机名访问您的服务。 您还可以尝试使用 IP 地址而不是主机名。

编辑: 不知何故,上述情况与负载平衡场景有关。 但是,如果无法删除主机条目,则禁用计算机上的环回检查将有所帮助。 请参考文章中的方法2 https://support.microsoft.com/en-us/kb/896861


2
这非常有用,迄今为止已经让我两次遇到了问题,因为服务在同一台机器上调用其他服务 :) - g7876413

4
我们遇到了这个问题,发现当使用(在我们的情况下是IE)以进程帐户登录的浏览器,然后通过应用程序(SharePoint)更改会话登录时,错误被抛出。 我相信这种情况可以通过两个身份验证方案进行验证:
  1. 协商
  2. NTLM
该应用程序托管了一个 *.asmx web 服务,并在负载均衡服务器上调用它,使用类似 WCF 的 .NET3.5 绑定启动了对自身的 web 服务调用。
用于调用 Web 服务的代码:
public class WebServiceClient<T> : IDisposable
{
    private readonly T _channel;
    private readonly IClientChannel _clientChannel;

    public WebServiceClient(string url)
        : this(url, null)
    {
    }
    /// <summary>
    /// Use action to change some of the connection properties before creating the channel
    /// </summary>
    public WebServiceClient(string url,
         Action<CustomBinding, HttpTransportBindingElement, EndpointAddress, ChannelFactory> init)
    {
        var binding = new CustomBinding();
        binding.Elements.Add(
            new TextMessageEncodingBindingElement(MessageVersion.Soap12, Encoding.UTF8));
        var transport = url.StartsWith("https", StringComparison.InvariantCultureIgnoreCase)
                            ? new HttpsTransportBindingElement()
                            : new HttpTransportBindingElement();
        transport.AuthenticationScheme = System.Net.AuthenticationSchemes.Ntlm;
        binding.Elements.Add(transport);

        var address = new EndpointAddress(url);

        var factory = new ChannelFactory<T>(binding, address);
        factory.Credentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;

        if (init != null)
        {
            init(binding, transport, address, factory);
        }

        this._clientChannel = (IClientChannel)factory.CreateChannel();
        this._channel = (T)this._clientChannel;
    }

    /// <summary>
    /// Use this property to call service methods
    /// </summary>
    public T Channel
    {
        get { return this._channel; }
    }
    /// <summary>
    /// Use this porperty when working with
    /// Session or Cookies
    /// </summary>
    public IClientChannel ClientChannel
    {
        get { return this._clientChannel; }
    }

    public void Dispose()
    {
        this._clientChannel.Dispose();
    }
}

我们发现,如果会话凭据与浏览器进程账户相同,则只使用NTLM并且调用成功。否则会导致以下捕获的异常:
“HTTP请求未经授权,客户端认证方案为'Ntlm'。从服务器接收到的身份验证标头是'Negotiate,NTLM'。”
最后,我非常确定其中一个身份验证方案将通过身份验证,而另一个身份验证方案则不会,因为它没有被授予适当的访问权限。

3
我知道这个问题很老,但对于我的应用程序,解决方案与已经提出的答案不同。如果还有像我一样的人遇到此问题,并且以上任何答案都无法解决,则可能是以下问题:
我使用了Network Credentials对象将Windows用户名+密码解析为第三方SOAP webservice。我设置了username="domainname\username",password="password"和domain="domainname"。现在这给了我奇怪的Ntlm而不是NTLM错误。 要解决问题,请确保不要在NetworkCredentials对象上使用域参数,如果域名包含在带反斜杠的用户名中。因此,要么从用户名中删除域名并解析域参数,要么省略域参数。这解决了我的问题。

2

1

我正在使用.NET 5。在我的情况下,我不得不将System.ServiceModel.Http.dll从4.8.1降级到4.4.4。没有太多时间深入挖掘根本原因。


请问您能分享一下您的代码吗?我在.NET 5中遇到了同样的问题。如果我添加用户名和密码,它可以工作,但是我正在尝试不使用用户名和密码来解决它。提前感谢您的帮助。 - Kavi

0
非常尷尬地承认,但希望能够帮助其他人避免类似的痛苦——我使用了一个Windows凭据,在系统中更改了该账户的密码,但没有更新从中提取凭据的位置。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接