如何使用存储的凭据调用Web服务?

时间:2009-06-15 01:35:26

标签: .net web-services security authentication

我需要调用在Windows域中运行的Web服务,该域服务与运行(Windows窗体)客户端的域不同。使用Windows身份验证保护Web服务。

Web服务域的域凭据保存在客户端的用户配置文件中(XP中保存的用户名和密码),但在调用Web服务时,我无法弄清楚如何使用这些保存的凭据。我找到了很多使用

的例子
WebService1.Credentials = System.Net.CredentialCache.DefaultCredentials 

(这不起作用,因为它是本地域的凭据)

WebService1.Credentials = new NetworkCredentials(username, pwd, domain) 

(用户名,密码,域名是硬编码的)。

我已经阅读了使用Windows API CredEnumerateCredRead的信息,但不知道如何(或者是否)将PCREDENTIAL转换为托管{{} 1}}(NetworkCredential不会返回存储域凭据的密码)

这里有人知道怎么做吗?

谢谢!

3 个答案:

答案 0 :(得分:1)

我不相信你可以直接使用它们。我相信你必须提示用户,然后一旦用户提供,你可以再次提示。 Here is an article on how to do that。毕竟,如果您可以从DPAPI获取凭据,那将失败目的。 :)

以下是一些信息。万一它有帮助...

在DPAPI中保存数据的管理员称为Key Manager。您可以通过执行start-> run ...

从UI访问密钥管理器
rundll32.exe keymgr.dll, KRShowKeyMgr

通常,存储身份验证功能的位置的API为ADVAPI32。您可以在那里找到帮助您的东西。这是API上的decent article

将凭据添加到CredentialCache时,您也可以尝试将authType "Negotiate"作为described here

对不起,这只是一个研究转储 - 我没有找到答案的地方,但希望其中一些可能对你有所帮助。 GL。

答案 1 :(得分:1)

好的,我找到了解决方案,所以我将回答我自己的问题:

首先,我发现通过使用新的WCF样式代理类“服务引用”允许您在app.config文件中设置安全设置。密钥(在我的方案中)是仅设置传输凭据的模式,将Windows指定为类型,并在领域属性中标识域:

<system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="Service1Soap" 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="TransportCredentialOnly">
                        <transport clientCredentialType="Windows" realm="mydomain.com" />
                    </security>
                </binding>
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://server.mydomain.com/HelloWorldSvc/Service1.asmx"
                binding="basicHttpBinding" bindingConfiguration="Service1Soap"
                contract="ServiceReference1.Service1Soap" name="Service1Soap" />
        </client>
    </system.serviceModel>

接下来,我使用Hernan de Lahitte's优秀的wrapper用于CredUIPromptForCredentials API函数,以便在抛出安全异常时提示用户输入凭据并将其存储在其配置文件中:

ServiceReference1.Service1SoapClient c = new Service1SoapClient();
retry:
try
{
    MessageBox.Show(this, c.HelloWorld());
}
catch (System.ServiceModel.Security.MessageSecurityException securityException)
{
    UserCredentialsDialog creds = new UserCredentialsDialog("*.mydomain.com", "My App",
                                                                        "Enter your enterprise credentials.  Enter your user name as \"MyDomain\\username\"");
    creds.Flags = UserCredentialsDialogFlags.Persist;
    if (creds.ShowDialog() == DialogResult.OK)
    {
        goto retry;
    }
}

c.Close();

是的,这是一个“转到”。 **** GASP ****:)

答案 2 :(得分:0)

我认为你不能在代码中使用它们,afaik你唯一的选择是:

  1. 硬编码你写的用户名/密码(在大多数情况下是一个很大的禁忌)。
  2. 在域和计算机之间使用Trust设置Kerberos,以便用户域帐户可以调用该服务。