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

49

我知道在stackoverflow上有很多类似的问题,但是我找不到一个针对这个特定问题的解决方案。

首先有几点需要注意:

  • 我对我们的Sharepoint服务器没有任何控制权,我无法调整任何IIS设置。
  • 我相信我们的IIS服务器版本是IIS 7.0。
  • 我们的Sharepoint服务器正在预期通过NTLM接收请求。
  • 我们的Sharepoint服务器与我的客户端计算机在同一个域中。
  • 我正在使用.NET Framework 3.5,Visual Studio 2008。

我试图编写一个简单的控制台应用程序,使用Sharepoint Web Services来操作Sharepoint数据。我已经添加了服务引用,下面是我的app.config:

<system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="ListsSoap" closeTimeout="00:01:00" openTimeout="00:01:00"
                receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
                bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
                maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
                useDefaultWebProxy="true">
                <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                    maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                <security mode="Transport">
                    <transport clientCredentialType="Ntlm" proxyCredentialType="Ntlm" />
                </security>
            </binding>
        </basicHttpBinding>
    </bindings>
    <client>
        <endpoint address="https://subdomain.companysite.com/subsite/_vti_bin/Lists.asmx"
            binding="basicHttpBinding" bindingConfiguration="ListsSoap"
            contract="ServiceReference1.ListsSoap" name="ListsSoap" />
    </client>
</system.serviceModel>
这是我的代码:
static void Main(string[] args)
{
    using (var client = new ListsSoapClient())
    {
        client.ClientCredentials.Windows.ClientCredential = new NetworkCredential("username", "password", "domain");
        client.GetListCollection();
    }
}

当我调用GetListCollection()时,会抛出以下MessageSecurityException

The HTTP request is unauthorized with client authentication scheme 'Ntlm'.
The authentication header received from the server was 'NTLM'.

有一个内部WebException:

"The remote server returned an error: (401) Unauthorized."

我尝试了各种绑定和代码调整来正确进行身份验证,但都没有成功。以下是我尝试过的步骤:


我尝试了以下步骤:

在创建客户端之前使用本机Win32模拟程序

using (new Impersonator.Impersonator("username", "password", "domain"))
using (var client = new ListsSoapClient())
{
    client.ClientCredentials.Windows.ClientCredential = new NetworkCredential("dpincas", "password", "domain");
    client.GetListCollection();
}

这产生了相同的错误消息。


为我的客户端凭据设置TokenImpersonationLevel

using (var client = new ListsSoapClient())
{
    client.ClientCredentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;
    client.GetListCollection();
}

这导致了相同的错误信息。


使用 security mode=TransportCredentialOnly

<security mode="TransportCredentialOnly">
    <transport clientCredentialType="Ntlm" />
</security>

这导致出现了另一种错误消息:

The provided URI scheme 'https' is invalid; expected 'http'.
Parameter name: via

然而,我需要使用https协议,因此无法更改我的URI scheme。


我尝试过一些其他的组合方式,但我现在想不起来了,等我想起来后会发布它们。我真的快崩溃了。我在谷歌上看到很多链接都说“切换到Kerberos”,但是我的服务器似乎只接受NTLM,而不是“Negotiate”(如果它正在寻找Kerberos,它会显示为“Negotiate”),所以这不是一个选项。

有人能帮忙吗?


也许这个问题更适合在这里提问:http://social.msdn.microsoft.com/Forums/en/category/sharepoint - BlueRaja - Danny Pflughoeft
另请参阅:https://dev59.com/uWUp5IYBdhLWcg3wCUCx https://dev59.com/6mYr5IYBdhLWcg3waJZT - MackM
10个回答

40

Visual Studio 2005

  1. 在 Visual Studio 中创建新的控制台应用程序项目。
  2. 添加 "Web 引用" 到 Lists.asmx Web 服务。
    • 你的 URL 可能看起来像: http://servername/sites/SiteCollection/SubSite/_vti_bin/Lists.asmx
    • 我将我的 Web 引用命名为:ListsWebService
  3. 在 program.cs 中编写代码(这里有一个 Issues 列表)。

以下是代码。

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;

namespace WebServicesConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                ListsWebService.Lists listsWebSvc = new WebServicesConsoleApp.ListsWebService.Lists();
                listsWebSvc.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
                listsWebSvc.Url = "http://servername/sites/SiteCollection/SubSite/_vti_bin/Lists.asmx";
                XmlNode node = listsWebSvc.GetList("Issues");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
    }
}

Visual Studio 2008

  1. 在 Visual Studio 中创建一个新的控制台应用程序项目。
  2. 右键单击“引用”,然后添加服务引用。
  3. 输入您服务器上 Lists.asmx 服务的 URL。
    • 例如:http://servername/sites/SiteCollection/SubSite/_vti_bin/Lists.asmx
  4. 点击“Go”。
  5. 点击“OK”。
  6. 进行以下代码更改:

将您的 app.config 文件从以下内容更改为:

<security mode="None">
    <transport clientCredentialType="None" proxyCredentialType="None"
        realm="" />
    <message clientCredentialType="UserName" algorithmSuite="Default" />
</security>

收件人:

<security mode="TransportCredentialOnly">
  <transport clientCredentialType="Ntlm"/>
</security>

修改 program.cs 文件并在 Main 函数中添加以下代码:

ListsSoapClient client = new ListsSoapClient();
client.ClientCredentials.Windows.ClientCredential = System.Net.CredentialCache.DefaultNetworkCredentials;
client.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
XmlElement listCollection = client.GetListCollection();

添加以下引用语句:

using [your app name].ServiceReference1;
using System.Xml;

参考资料: http://sharepointmagazine.net/technical/development/writing-caml-queries-for-retrieving-list-items-from-a-sharepoint-list


@ Kit Menke,我编辑了app.config文件,因为我遇到了这个错误:HTTP请求未经授权,客户端身份验证方案为“匿名”。从服务器接收到的身份验证标头是“NTLM”。 我需要将app.config中的<transport>元素从clientCredentialType="None" proxyCredentialType="None"更改为clientCredentialType="Ntlm" proxyCredentialType="Ntlm"。 然而,所有这些只是给我带来了不同的错误消息 :-) - Pandincus
还要注意他不同的访问列表方式 - 在消费SP Web服务的代码中,我从未引用soap。我只是在Visual Studio中添加Web引用,并像Kit上面那样访问它。 - Mayo
感谢您更新示例,Kit。您的示例目前与我的最新代码版本完全相同。我相信这个问题实际上是我们MOSS设置的问题,与代码无关 :-(不幸的是,我仍在等待我们的服务器人员回复,以找出问题所在。我的意图是一旦他们告诉我他们修复了什么,就用“服务器”解决方案更新这个问题。 - Pandincus
如何为消耗自定义Web服务的简单Windows应用程序进行身份验证? - code master

8

经过多次尝试,加上在等待与我们的服务器人员交谈的机会时停滞不前,我终于有机会与他们讨论问题,并询问他们是否愿意将我们的Sharepoint身份验证切换到Kerberos。

令我惊讶的是,他们说这不是问题,而且很容易做到。 他们启用了Kerberos,我按照以下方式修改了我的app.config:

<security mode="Transport">
    <transport clientCredentialType="Windows" />
</security>

供参考,我的app.config文件中完整的serviceModel条目如下:

<system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="TestServerReference" closeTimeout="00:01:00" openTimeout="00:01:00"
             receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
             bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
             maxBufferSize="2000000" maxBufferPoolSize="2000000" maxReceivedMessageSize="2000000"
             messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
             useDefaultWebProxy="true">
                <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                 maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                <security mode="Transport">
                    <transport clientCredentialType="Windows" />
                </security>
            </binding>
        </basicHttpBinding>
    </bindings>
    <client>
        <endpoint address="https://path/to/site/_vti_bin/Lists.asmx"
         binding="basicHttpBinding" bindingConfiguration="TestServerReference"
         contract="TestServerReference.ListsSoap" name="TestServerReference" />
    </client>
</system.serviceModel>

之后,一切都顺利地运作了。我现在终于可以使用Sharepoint Web Services了!因此,如果有其他人无法通过NTLM让他们的Sharepoint Web Services正常工作,请尝试说服系统管理员转换到Kerberos。


5
经过多次尝试都无法解决的问题,在我们的IIS服务器上禁用匿名访问后终于找到了一个解决方案。我们的服务器使用Windows身份验证,而不是Kerberos。这要感谢 这篇博客文章
没有对web.config进行任何更改。
在服务端,位于ISAPI文件夹中的.SVC文件使用MultipleBaseAddressBasicHttpBindingServiceHostFactory。
服务的类属性如下:
[BasicHttpBindingServiceMetadataExchangeEndpointAttribute]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class InvoiceServices : IInvoiceServices
{
...
}

在客户端,使其工作的关键是http绑定安全属性:
EndpointAddress endpoint =
  new EndpointAddress(new Uri("http://SharePointserver/_vti_bin/InvoiceServices.svc"));
BasicHttpBinding httpBinding = new BasicHttpBinding();
httpBinding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
httpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm;
InvoiceServicesClient myClient = new InvoiceServicesClient(httpBinding, endpoint);
myClient.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation; 

(call service)

我希望这对你有所帮助!

3

如果我没记错的话,将SharePoint web服务添加为VS2K8“Service Reference”存在一些问题。您需要将其添加为旧式的“Web Reference”才能正常工作。


谢谢!我总是忘记这种旧式对话框的存在。 - Alexander Prokofyev

2
我跟你的设置一样,这对我来说可以正常工作。我认为问题可能出在你的moss配置或网络上。 你说moss和你的应用程序在同一个域中。如果你可以通过使用你的用户(已登录到你的计算机)访问该站点...你尝试过吗:
client.ClientCredentials.Windows.ClientCredential = System.Net.CredentialCache.DefaultNetworkCredentials;

2

我以前也遇到过这个问题。

client.ClientCredentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;

在调用之前,请对您的WCF代理执行以下操作。

2

上周我遇到了完全相同的问题-WCF程序在一个服务器上表现异常,为什么?

对我来说,解决方案非常简单。Sharepoint有自己的权限设置。我的客户尝试以未经过Sharepoint管理面板明确授予访问webservice权限的用户身份登录。

我将该用户添加到Sharepoint的白名单中,嘭——它就可以工作了。

即使这不是问题所在,请注意:

HTTP请求未经客户端身份验证方案'Ntlm'进行授权。从服务器收到的身份验证标头是'NTLM'。

意味着(用英语)您只是没有权限。您的协议可能是正确的——您的用户只是没有权限。


1
在某些情况下可能是正确的,但在我的情况下,至少根据服务器管理员的说法,我拥有完全的权限。真的很不幸,这个错误信息(显然)意味着很多不同的事情! - Pandincus
该用户登录时在内部SharePoint权限数据库中具有对您尝试拉取的SharePoint项目的完全权限? - diadem
这个管理员面板在哪里,可以明确地给用户访问Web服务的权限? - xr280xr

2
我建议您使用这个工具这里尝试连接到您的Sharepoint网站。如果可以连接成功,那么您可以确定问题出在您的代码/配置上。虽然这并不能立即解决您的问题,但可以排除服务器出现故障的可能性。如果连接测试失败,我建议您考虑以下情况:
  • 你的用户是否真的拥有足够的权限访问该站点?
  • 是否存在干扰的代理?(您的配置看起来像是存在代理。您能否绕过它?)
我认为使用安全模式传输没有问题,但对于proxyCredentialType="Ntlm",我不是很确定,也许应该将其设置为

1
很棒的工具!不幸的是,它无论我选择“当前用户”还是我的域用户名/密码,都会产生完全相同的错误。 这个问题现在有点老了,我确实怀疑这是一个服务器问题,并联系了我们的服务器管理员。他们设置了一个正常工作的开发站点,并向我保证他们会“调查”我们的现场问题。仍在等待他们的回复... - Pandincus

0

试试这个

<client>
  <endpoint>
    <identity>
      <servicePrincipalName value="" />
    </identity>
  </endpoint>
</client>

我之前在 webfarm 工作时也遇到过这个错误,这个方法对我有用。


0
这个问题对我们来说更加奇怪。如果您在进行SOAP调用之前已经从浏览器访问了Sharepoint站点,则一切都正常。但是,如果您首先进行SOAP调用,我们将抛出上述错误。
我们通过在客户端安装Sharepoint证书并将域添加到本地内部网站中来解决此问题。

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