在这个由三部分组成的传奇中,我将演示如何使用SoapUI API工具来调用安全的SOAP服务。 首先,我将专注于创建服务,在接下来的文章中它将充当被测系统。
使用基本身份验证传输安全性机制维护对该服务中资源的访问。 Windows Communication Foundation 提供的众多功能之一。 这种机制与HTTPS结合使用以提供机密性。
WCF基本身份验证服务
要实现的服务包含一个端点,用于计算很大的一笔费用 。 为了快速入门,我们将使用Visual Studio 2019中提供的WCF服务应用程序的默认模板。
在菜单文件中,依次单击新建,项目,或单击开始页面开始一个新项目。 让我们将解决方案和项目命名为AVeryBigSum 。
现在,您将看到已经添加到WCF服务项目中的几个文件。 我们可以选择删除接口IService1.cs和服务Service1.svc文件来创建新文件。 否则,我们可以重命名这两个文件,因此请注意重命名以及Service.svc文件的标记,方法是右键单击它->“ 查看标记”并更改为以下名称。
<%@ ServiceHost Language="C#" Debug="true"
Service="AVeryBigSum.Avbs" CodeBehind="Avbs.svc.cs" %>
重命名两个文件后,打开IAvbs.cs,复制以下代码并将其添加到修改后的界面中。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
namespace AVeryBigSum
{
[ServiceContract]
public interface IAvbs
{
[OperationContract]
long AVeryBS(long[] ar);
}
}
如果您选择删除这些文件,则可以通过右键单击项目并添加新项来添加新界面。 选择接口模板并将其重命名为IAvbs。 同样,您需要复制上面的代码并将其添加到新创建的界面中。
该服务仅实现接口协定中定义的一项操作。 要实现它,我们需要修改VStudio创建的默认文件或添加一个新服务类Avbs.svc,它将实现上面定义的接口。
using System;
/*...*/
namespace AVeryBigSum
{
public class Avbs : IAvbs
{
public long AVeryBS(long[] ar)
{
long aVeryBigSum = 0;
foreach (long i in ar) aVeryBigSum += i;
return aVeryBigSum;
}
}
}
到目前为止,我们已经定义了服务合同,即带有示例定义的操作。 现在我们必须定义其端点。 要添加端点,我们需要更改配置文件(web.config)。 除了复制和粘贴外,我们还需要了解每个WCF标签的重要性。
使用SoapUI保护WCF SOAP – AppSettings
因此,让我们从AppSettings元素开始。 此元素包含自定义应用程序设置。 该元素存储定制应用程序配置信息,例如数据库连接字符串,文件路径,XML Web服务URL或应用程序的任何其他定制配置信息。
我们使用此元素来存储服务的用户和密码凭据。 使用ConfigurationSettings库以这种方式在代码中访问元素中指定的键/值对,即ConfigurationManager.AppSettings [“ AVeryBigSum_User”]。
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
<add key="AVeryBigSum_User" value="AVeryBigSum"/>
<add key="AVeryBigSum_Pass" value="12345"/>
</appSettings>
因此,我们可以更改这些凭据,而无需重建项目的动态链接库文件 (DLL)。
尽管使用上述元素具有优势,但与服务的定义有关的所有魔术都发生在ServiceModel标记的边界中。
使用SoapUI保护WCF SOAP的行为
该标签定义了端点和服务分别消耗的协议元素。 服务凭证元素对于定义至关重要。 它指定了身份验证过程中使用的自定义验证模式。
<behaviors>
<serviceBehaviors>
<behavior name="DebugModeBehavior">
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="true"/>
<!--For UserPass Authentication-->
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="AVeryBigSum.ServiceAuthenticator, AVeryBigSum"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
在服务凭证 s中,定义了另一个重要属性,用于指定用户名和密码验证的设置。 userNamePasswordValidationMode属性设置如何验证凭据。 我们的服务使用自定义类来验证凭据。 此类AVeryBigSum.ServiceAuthenticator可在AVeryBigSum项目中找到。
使用SoapUI保护WCF SOAP –绑定
WCF服务中的每个终结点都需要明确指定绑定。 绑定由绑定元素的有序堆栈组成,每个绑定元素指定连接到服务端点所需的一部分通信信息。
如我们所见,我们正在使用WSHttpBinding。 它表示可互操作的绑定,该绑定支持分布式事务,安全,可靠的会话。
<bindings>
<wsHttpBinding>
<!-- configure wsHttp binding with Transport security mode and clientCredentialType as Certificate -->
<binding name="wsHttpBinding_LargeBinding" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" bypassProxyOnLocal="false"
transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="250000000" maxReceivedMessageSize="250000000" messageEncoding="Text"
textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
<readerQuotas maxDepth="2000000" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
<reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false"/>
<!--For UserPass Authentication-->
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" establishSecurityContext="false"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
WSHttpBinding使用HTTP传输并提供消息安全性,事务,可靠的消息传递和WS-Addressing,它们是默认启用的,也可以通过单个控件设置使用。
在WSHttpBinding元素内部,我们将安全模式定义为TransportWithMessageCredential。 传输确定提供传输级别安全性的实际机制。 对于HTTP,该机制是基于HTTP(HTTPS)的安全套接字层(SSL);
使用SoapUI保护WCF SOAP –服务
最后,在服务元素上,我们定义了终结点,公开了服务元数据。 发布元数据(如描述服务使用的所有方法和数据类型的Web服务描述语言(WSDL)文档)很有用。 SoapUi将在此传奇的下一篇文章中使用它来检索和调用所有可服务的端点。
<services>
<service behaviorConfiguration="DebugModeBehavior" name="AVeryBigSum.Avbs">
<endpoint address="endpointAVeryBigSum" binding="wsHttpBinding"
bindingConfiguration="wsHttpBinding_LargeBinding" name="EndpointAVeryBigSum"
contract="AVeryBigSum.IAvbs" />
<endpoint address="mex" binding="wsHttpBinding" bindingConfiguration="wsHttpBinding_LargeBinding"
name="mexEndpoint" contract="IMetadataExchange" />
</service>
</services>
使用SoapUI保护WCF SOAP –自定义验证器类
定制验证器扩展了UserNamePasswordValidator类,并覆盖了Validate方法。 该验证器在“服务行为”中定义为默认授权管理器,如上面行为部分中所示。 此类将客户端调用接收到的信息与AppsSetting元素中定义的信息进行比较。
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IdentityModel.Selectors;
using System.Linq;
using System.ServiceModel;
using System.Web;
namespace AVeryBigSum
{
public class ServiceAuthenticator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password))
throw new SecurityTokenException("Username and password required");
if (!(userName == ConfigurationManager.AppSettings["AVeryBigSum_User"] && password == ConfigurationManager.AppSettings["AVeryBigSum_Pass"]))
throw new FaultException(string.Format("Wrong username ({0}) or password ", userName));
}
}
}
为了使此类正常工作,我们需要在项目中添加两个外部库。 我们可以通过右键单击项目-> Manage NuGet Packages,浏览Microsoft.IdentityModel.Logging和Microsoft.IdentityModel.Tokens软件包并添加两者来完成此操作。
现在我们已经定义了端点,接下来,我们将服务托管在本地开发服务器中。
部署并运行服务
1 –要将我们的服务托管在IIS中,请右键单击该项目,然后转到“ 属性” 。 在属性窗口中,选择“ Web”选项卡。
2-现在在“ Web上的服务器”设置下,您将看到以下详细信息,将“ IIS Express”更改为“ IIS Server”。
3 –现在,单击使用以管理员身份运行的Visual Studio创建虚拟目录。 您将收到一条消息:虚拟目录已成功创建! 否则,您将收到一条错误消息,并且需要以管理员身份再次启动Visual Studio。
现在按F5键,您的应用程序将在IIS服务器而不是IIS express上启动并运行。
结论
在本演示结束时,我们将提供一个由SoapUi调用的安全服务。 我们的下一篇文章将逐步演示如何做到这一点。
另外,可以从GitHub存储库访问该示例; 要下载它,请点击此链接 。