如何在具有 WCF 服务参考的客户端中使用 IssuedToken

Posted

技术标签:

【中文标题】如何在具有 WCF 服务参考的客户端中使用 IssuedToken【英文标题】:How to use IssuedToken in a client with a WCF Service Reference 【发布时间】:2013-01-28 12:23:20 【问题描述】:

我有一个 WinForms 应用程序,其中包含从使用 WS2007FederationHttpBinding 的 WCF 服务生成的服务引用。我不明白为什么以下不起作用。

我的 WinForms 应用正在调用 WCF 服务,该服务使用 Thinktecture.IdentityServer,设置为处理 BearerKey 类型令牌。

我只是从我的客户那里获得了一个有效的访问令牌,然后调用:

    private static void CallServiceReference(SecurityToken token)
    
        ServiceReference1.ClaimsServiceContractClient svcRef = new ServiceReference1.ClaimsServiceContractClient();

        svcRef.ChannelFactory.Credentials.SupportInteractive = false;
        svcRef.ChannelFactory.CreateChannelWithIssuedToken(token);
        var claims = svcRef.GetClaims(); 
    

这是服务参考的 winforms 客户端 app.config:

<system.serviceModel>
      <bindings>
              <ws2007FederationHttpBinding>
                      <binding name="WS2007FederationHttpBinding_ClaimsServiceContract">
                              <security mode="TransportWithMessageCredential">
                                      <message establishSecurityContext="false" issuedKeyType="BearerKey">
                                              <issuer address="https://identity.MyCo.com/issue/wsfed" binding="ws2007HttpBinding"
                                                      bindingConfiguration="https://identity.MyCo.com/issue/wstrust/mixed/username" />
                                              <issuerMetadata address="https://identity.MyCo.com/issue/wstrust/mex" />
                                              <tokenRequestParameters>
                                                      <trust:SecondaryParameters xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
                                                              <trust:KeyType xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</trust:KeyType>
                                                              <trust:CanonicalizationAlgorithm xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">http://www.w3.org/2001/10/xml-exc-c14n#</trust:CanonicalizationAlgorithm>
                                                              <trust:EncryptionAlgorithm xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">http://www.w3.org/2001/04/xmlenc#aes256-cbc</trust:EncryptionAlgorithm>
                                                      </trust:SecondaryParameters>
                                              </tokenRequestParameters>
                                      </message>
                              </security>
                      </binding>
              </ws2007FederationHttpBinding>
              <ws2007HttpBinding>
                      <binding name="https://identity.MyCo.com/issue/wstrust/mixed/username">
                              <security mode="TransportWithMessageCredential">
                                      <transport clientCredentialType="None" />
                                      <message clientCredentialType="IssuedToken" establishSecurityContext="false" />
                              </security>
                      </binding>
              </ws2007HttpBinding>
      </bindings>
      <client>
              <endpoint address="https://roadie/WebTest/service.svc" binding="ws2007FederationHttpBinding"
                      bindingConfiguration="WS2007FederationHttpBinding_ClaimsServiceContract"
                      contract="ServiceReference1.ClaimsServiceContract" name="WS2007FederationHttpBinding_ClaimsServiceContract" />
      </client>
  </system.serviceModel>

当我尝试执行服务调用 (svcRef.GetClaims()) 时,我收到此错误:

“未指定安全令牌颁发者的地址。必须在目标“https://identity.MyCo.com/issue/wsfed”的绑定中指定明确的颁发者地址,或者必须在凭据中配置本地颁发者地址。”

这个错误很蹩脚,而且令人困惑,似乎在配置中指定了一个发行者!

最后,我知道 WCF 服务和身份服务是有效的,因为这一切都可以使用自定义 ChannelFactory 正常工作,也使用完全相同的方法来应用令牌:

var channel = factory.CreateChannelWithIssuedToken(token);

但我的要求是使用生成的 ServiceReference。 :(

【问题讨论】:

【参考方案1】:

有时您没有引用的客户端存根 DLL,那么您可以使用反射来动态加载和调用它。 这是使用已颁发令牌创建客户端的反射版本:

//Our goal is to get a client obj from reflection
//var obj = client.ChannelFactory.CreateChannelWithIssuedToken(token);

double value1 = 2;
double value2 = 3;
//this line needs to be changed to be created from reflection if needed
CalculatorClient cc = new CalculatorClient("WS2007FederationHttpBinding_ICalculator"); var pi = cc.GetType().GetProperty("ChannelFactory"); //proprety 
var factoryObj = pi.GetValue(cc);
var mi = factoryObj.GetType().GetMethod("CreateChannelWithIssuedToken", new Type[]  typeof(SecurityToken)); //method info
var clientObj = mi.Invoke(factoryObj, new object[]  token );
mi = clientObj.GetType().GetMethod("Add"); //another method info
var result = mi.Invoke(clientObj, new Object[]  2, 3 );
Console.WriteLine("Add(0,1) = 2", value1, value2, Convert.ToDouble(result));

【讨论】:

【参考方案2】:

您应该像这样使用创建的频道:

private static void CallServiceReference(SecurityToken token)

    ServiceReference1.ClaimsServiceContractClient svcRef = 
        new ServiceReference1.ClaimsServiceContractClient();

    svcRef.ChannelFactory.Credentials.SupportInteractive = false;
    var svcChannel = svcRef.ChannelFactory.CreateChannelWithIssuedToken(token);
    var claims = svcChannel.GetClaims();

【讨论】:

【参考方案3】:

我认为您可以使用从服务参考生成的代理的唯一方法是,您将客户端配置为自动请求令牌并在进行服务调用之前在您创建的代理实例上设置适当的 ClientCredentials 属性。

在我从事的项目中,我们正在使用缓存在客户端上的已发布令牌,但随后我们必须使用通道工厂 CreateChannelWithIssuedToken,正如您所描述的那样。

顺便说一句,这是在 .NET 4.0 中使用 WIF 时。如果在 .NET 4.5 上运行,也许还有其他选择。

【讨论】:

以上是关于如何在具有 WCF 服务参考的客户端中使用 IssuedToken的主要内容,如果未能解决你的问题,请参考以下文章

WCF与相互身份验证

如何在WCF的IDispatchMessageInspector中获取调用方法?

如何在 WCF 客户端中接受自签名 SSL 证书?

如何为具有共享类型的多个 WCF 服务生成客户端代码

如何在 Restful WCF 服务中管理会话

VB6 连接到 WCF