简体   繁体   English

Royal Mail Shipping API v2 SOAP身份验证C#

[英]Royal Mail Shipping API v2 SOAP authentication C#

I've done most of the work based on other people's code on stack overflow. 我已经根据其他人在堆栈溢出时的代码完成了大部分工作。 See below. 见下文。

My current issue is that I'm still getting authorization failure and I can clearly see why. 我当前的问题是我仍然遇到授权失败的问题,我可以清楚地知道原因。 v2 API requires X-IBM-Client-Id and X-IBM-Client-Secret to be passed as well as SOAP security header. v2 API要求传递X-IBM-Client-Id和X-IBM-Client-Secret以及SOAP安全标头。 However, I don't know how to inject it while using service created from Wsdl file. 但是,我不知道在使用从Wsdl文件创建的服务时如何注入它。

Solved problems: 解决的问题:

Overcame namespaces problem (using message formatter Consume WCF Royal Mail API in c# Console Application ). 克服了名称空间问题( 在c#控制台应用程序中使用消息格式化程序Consuming WCF Royal Mail API )。

Solved binding configuration problem which results in two security headers. 解决了绑定配置问题,该问题导致两个安全头。 Also, you must set maxReceivedMessageSize if you want to get no exception while retrieving label.Final binding: 另外,如果要在获取标签时不出现异常,则必须设置maxReceivedMessageSize。最终绑定:

<system.serviceModel> <bindings> <basicHttpBinding> <binding name="basicBindingTransport" maxReceivedMessageSize="2147483647"> <security mode="Transport"> </security> </binding> </basicHttpBinding> </bindings> <client> <endpoint address="https://api.royalmail.net/shipping/v2" binding="basicHttpBinding" bindingConfiguration="basicBindingTransport" contract="RoyalMailApiWsdl.shippingAPIPortType" name="shippingAPIPort" /> </client> </system.serviceModel>

Solved E0007 Authorization Failure. 解决了E0007授权失败。

Solved The HTTP request is unauthorized with client authentication scheme 'Anonymous' (you must use the binding as above with security "Transport" and inject credentials directly into http post header itself (See my answer below). 解决了HTTP请求未经客户端身份验证方案'Anonymous'的未经授权(您必须使用具有安全性“ Transport”的上述绑定,并将凭据直接注入到http post标头本身中(请参阅下面的答案)。

And many other issues, which I cannot remember now. 还有许多其他问题,我现在不记得了。 I hope this post will help others. 希望这篇文章对其他人有帮助。

To implement double authentification in the Shipping API v2, you can use this code (the idea taken from How to add custom Http Header for C# Web Service Client consuming Axis 1.4 Web service ) 要在Shipping API v2中实现双重身份验证,您可以使用此代码(该思想来自如何为使用Axis 1.4 Web服务的C#Web服务客户端添加自定义Http标头

shippingAPIPortTypeClient client = GetProxy();
<..>
using (OperationContextScope scope = new OperationContextScope(client.InnerChannel))
{
    var httpRequestProperty = new HttpRequestMessageProperty();
    httpRequestProperty.Headers.Add(@"X-IBM-Client-Id", _credentials.HttpSecurity.ClientId);
    httpRequestProperty.Headers.Add(@"X-IBM-Client-Secret", _credentials.HttpSecurity.ClientSecret);
    OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = httpRequestProperty;

    createShipmentResponse response = client.createShipment(GetSecurityHeaderType(), request);
    return response;
}

private shippingAPIPortTypeClient GetProxy()
{
    // binding comes from configuration file
    var shippingClient = new shippingAPIPortTypeClient();

    shippingClient.ClientCredentials.UserName.UserName = _credentials.SoapSecurity.Username;
    shippingClient.ClientCredentials.UserName.Password = _credentials.SoapSecurity.Password;

    shippingClient.ClientCredentials.UseIdentityConfiguration = true;

    foreach (OperationDescription od in shippingClient.Endpoint.Contract.Operations)
    {
        od.Behaviors.Add(new RoyalMailIEndpointBehavior());
    }

    return shippingClient;
}

private SecurityHeaderType GetSecurityHeaderType()
{
    SecurityHeaderType securityHeader = new SecurityHeaderType();

    DateTime created = DateTime.Now;

    string creationDate;
    creationDate = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ");

    string nonce = nonce = (new Random().Next(0, int.MaxValue)).ToString();

    byte[] hashedPassword;
    hashedPassword = GetSHA1(_credentials.SoapSecurity.Password);

    string concatednatedDigestInput = string.Concat(nonce, creationDate, Encoding.Default.GetString(hashedPassword));
    byte[] digest;
    digest = GetSHA1(concatednatedDigestInput);

    string passwordDigest;
    passwordDigest = Convert.ToBase64String(digest);

    string encodedNonce;
    encodedNonce = Convert.ToBase64String(Encoding.Default.GetBytes(nonce));

    XmlDocument doc = new XmlDocument();
    using (XmlWriter writer = doc.CreateNavigator().AppendChild())
    {
        writer.WriteStartDocument();
        writer.WriteStartElement("Security");
        writer.WriteStartElement("UsernameToken", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
        writer.WriteElementString("Username", _credentials.SoapSecurity.Username);
        writer.WriteElementString("Password", passwordDigest);
        writer.WriteElementString("Nonce", encodedNonce);
        writer.WriteElementString("Created", creationDate);
        writer.WriteEndElement();
        writer.WriteEndElement();
        writer.WriteEndDocument();
        writer.Flush();
    }

    doc.DocumentElement.RemoveAllAttributes();

    System.Xml.XmlElement[] headers = doc.DocumentElement.ChildNodes.Cast<XmlElement>().ToArray<XmlElement>();

    securityHeader.Any = headers;

    return securityHeader;

}

On top of that complete working Royal Mail Shipping API v2 solution in C# is available here: https://github.com/povilaspanavas/RoyalMailShippingApiV2 在此,可以使用C#完整,有效的Royal Mail Shipping API v2解决方案: https//github.com/povilaspanavas/RoyalMailShippingApiV2

It has three tests, one to create local (GB) shipment, another international, and the third to retrieve label pdf file. 它具有三个测试,一个用于创建本地(GB)货件,另一个用于国际测试,第三种用于检索标签pdf文件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM