策略文件基于 WS-Policy 规范,该规范是为允许 Web 服务声明传入消息有关安全性等方面的要求而创建的。如果希望签名或者加密所有或部分消息,WSE 2.0 允许我们控制 Web 服务的用户在消息中使用的安全令牌类别,以及控制对接收消息时限的限制,甚至可以为传入的消息指定角色成员限制。
以下策略文件说明 Web 服务接收的消息应使用 Kerberos 令牌对消息主体进行签名。
<?xml version="1.0" encoding="utf-8"?>
<policyDocument
xmlns="http://schemas.microsoft.com/wse/2003/06/Policy">
<mappings
xmlns:wse="http://schemas.microsoft.com/wse/2003/06/Policy">
<mapDefault
policy="#policy-5903e02b-9c11-4dc5-8ca0-42d4e9d0bcde" />
</mappings>
<policies
xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility">
<wsp:Policy
wsu:Id="policy-5903e02b-9c11-4dc5-8ca0-42d4e9d0bcde"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2002/12/policy">
<wsse:Integrity wsp:Usage="wsp:Required"
xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/12/secext">
<wsse:TokenInfo>
<SecurityToken
xmlns="http://schemas.xmlsoap.org/ws/2002/12/secext">
<wsse:TokenType>wsse:Kerberosv5ST</wsse:TokenType>
</SecurityToken>
</wsse:TokenInfo>
<wsse:MessageParts
Dialect="http://schemas.xmlsoap.org/2002/12/wsse#part">
wsp:Body()
</wsse:MessageParts>
</wsse:Integrity>
</wsp:Policy>
</policies>
</policyDocument>
policyDocument 根元素有两个子元素:mappings 和 policies。policies 元素含有一个或多个表示特定要求集的 Policy 元素。在示例中,策略包含一个 Integrity 要求,表示该消息需要数字签名。TokenInfo 元素包含关于所需令牌种类的信息,本示例中为 Kerberos 令牌。最后,这一特定完整性要求指出必须签名的文档部分为正文,这是使用 MessageParts 元素指示的。
policyDocument 的 mappings 部分仅将特定终结点与 policies 部分中的策略关联。本示例不包括特定终结点的任何映射,仅包括单一的默认映射。
除了实际创建策略文件以外,还需要让 WSE 程序库知道该策略的存在。因此,有必要配置 Web 服务以使用创建的策略文件。为此,需要修改 Web.config 文件。下面的 Web.config 文件给出了为启用 WSE SoapExtension、启用 WSE 配置部分中的处理程序以及添加接收策略缓存而作的更改。
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- 添加对配置部分的引用。 请注意,
类型名称要换行以便于阅读,并且不应包含
换行符。-->
<section name="microsoft.web.services"
type="Microsoft.Web.Services.Configuration
.WebServicesConfiguration, Microsoft.Web.Services,
Version=2.0.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35" />
</configSections>
<system.web>
<!-- 为了简洁,删除其他元素 -->
<webServices>
<soapExtensionTypes>
<!-- 添加 WSE SoapExtension。请注意,
类型名称要换行以便于阅读并且
不应包含换行符。-->
<add type="Microsoft.Web.Services
.WebServicesExtension, Microsoft.Web.Services,
Version=2.0.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35"
priority="1" group="0" />
</soapExtensionTypes>
</webServices>
</system.web>
<!-- WSE Configuration Section -->
<microsoft.web.services>
<policy>
<receive>
<cache name="policyCache.xml" />
</receive>
</policy>
</microsoft.web.services>
</configuration>
至此,已将 Web 服务配置成只接受符合 policyCache.xml 文件中策略要求的请求。
如果需要让管理员为特定的 Web 服务配置策略,我们同样希望对使用 Web 服务的应用程序进行类似配置。总而言之,如果管理员更改策略后我们必须重新生成使用的应用程序,则并没有完全实现配置消息要求时无需重新生成 Web 服务的功能。
要为使用的应用程序添加该功能来发送符合特定策略的消息,需要本地具有该程序可以使用的策略文件。对于要调用 .asmx Web 服务的 Rock Paper Scissors 对等应用程序,我们只是将 policyCache.xml 文件复制到该可执行程序的工作目录。如同对 Web 服务的处理,将该应用程序配置成使用其 .config 文件中的策略文件(本示例中为 RockPaperScissors.exe.config)。该配置文件如下所示。
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- 添加对配置部分的引用。请注意,
类型名称要换行以便于阅读,并且不应包含
换行符。-->
<section name="microsoft.web.services"
type="Microsoft.Web.Services.
Configuration.WebServicesConfiguration,
Microsoft.Web.Services, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</configSections>
<microsoft.web.services>
<policy>
<send>
<cache name="policyCache.xml" />
</send>
</policy>
</microsoft.web.services>
</configuration>
对等应用程序将通过发送符合 policyCache.xml 文件中的要求的消息与 Web 服务进行通信。
WSE 2.0 寻址
WSE 1.0 与 WSE 2.0 之间的区别之一是对 WS-Addressing 的支持。WS-Addressing 替换了 WSE 1.0 中支持的 WS-Routing 规范的大部分功能。从功能方面来说,WS-Addressing 不是将重点放在路由路径上,而是提供一种机制将 To 和 From 标头添加到 SOAP 信封中。WS-Addressing 也支持 Action、ReplyTo 和 FaultTo 标头。Action 标头类似于通过 HTTP 发送 SOAP 消息时通常使用的 SOAPAction HTTP 标头。对于 .asmx Web 服务,HTTP SOAPAction 标头用于确定接收传入消息时应调用服务的哪种 Web 方法。与此类似,Action SOAP 标头用于确定通过非 HTTP 传输接收消息时要调用的函数。
在 Rock Paper Scissors 应用程序中,我们还将利用 ReplyTo 标头来确定接收下一消息的地址。当对等应用程序之一向 RPSService 发送单向 RegisterPlayer 消息时,将指定一个 ReplyTo 终结点,指示对等通信开始时用来接收对方发送的消息的地址。与此类似,当第二个对等应用程序将 FindPlayer 消息发送到 RPSServer 时,RPSServer 将返回一个带有 ReplyTo 标头的消息,该标头指示第一个对等应用程序的终结点。这就告诉第二个对等应用程序应该将自己的下一消息发送到第一个对等应用程序的终结点。在余下的对等消息中,继续指定 ReplyTo 标头来不断指示接收下一消息的地址。
下面是对等应用程序使用的部分代码,在代码中,首先侦听对等通信,然后在调用 RPSServer RegisterPlayer Web 方法之前通过 ReplyTo 标头指示 URI。
myPeerUri
= new Uri("soap.tcp://"
+ System.Net.Dns.GetHostName()
+ ":3131/RPSPeer1");
SoapReceivers.Add(myPeerUri, typeof(PeerService));
RPSServ.RPSServerWse proxy = new RPSServ.RPSServerWse();
proxy.RequestSoapContext.ReplyTo = myPeerUri;
TCP 消息处理
在 WSE 2.0 中,消息处理是新增功能的主要部分。WSE 2.0 通过异步 TCP 或请求/响应方式 TCP 为进程中的通信提供支持。在本示例的 Rock Paper Scissors 应用程序中,我们将发送消息来指示玩家对于特定游戏实例是否选择了石头、布或剪刀。由于我们依靠用户交互来确定发送消息的内容,我们不可能无限地等待需要发送响应的请求,因此,我们使用异步 TCP 消息来实现特定游戏的通信。一个人发送其动作后应用程序耐心的等待,直到对方玩家发送其动作。您可以将这看作类似于向仓库发送发货单,必须等待,直到有人手动包装材料,才能发送一个指示请求完成的响应。