如何:为安全会话创建安全上下文令牌
通过在安全会话中使用有状态安全上下文令牌 (SCT),可以使该会话避免因为重新使用服务而受到影响。 例如,如果在安全会话中使用了无状态 SCT 并且 Internet 信息服务 (IIS) 被重置,则与该服务相关联的会话数据将丢失。 这些会话数据包括一个 SCT 令牌缓存。 因此,当客户端下一次向该服务发送无状态 SCT 时,将返回错误,这是因为无法检索到与该 SCT 相关联的密钥。 但是,如果使用有状态 SCT,则与该 SCT 相关联的密钥将包含在该 SCT 中。 由于密钥包含在 SCT 中并因而包含在消息中,因此安全会话不会因为重新使用服务而受到影响。 默认情况下,Windows Communication Foundation (WCF) 在安全会话中使用无状态 SCT。 本主题详细介绍如何在安全会话中使用有状态 SCT。
注意
如果安全会话涉及到派生自 IDuplexChannel 的协定,则无法在该安全会话中使用有状态 SCT。
注意
对于在安全会话中使用有状态 SCT 的应用程序,服务的线程标识必须是具有关联用户配置文件的用户帐户。 如果服务在不具有用户配置文件的帐户下运行(如 Local Service
),则可能引发异常。
备注
当需要在 Windows XP 上进行模拟时,请不要在安全会话中使用有状态 SCT。 如果在模拟时使用有状态 SCT,则会引发 InvalidOperationException。 有关详细信息,请参阅不支持的方案。
在安全会话中使用有状态 SCT
创建一个自定义绑定,该绑定指定由使用有状态 SCT 的安全会话来保护 SOAP 消息。
定义一个自定义绑定,方法是通过向服务的配置文件添加一个 <customBinding>。
<customBinding> </customBinding>
向 <customBinding> 添加一个 <binding> 子元素。
通过在配置文件中将
name
属性设置为一个唯一的名称,指定一个绑定名称。<binding name="StatefulSCTSecureSession"> </binding>
通过将一个 <security> 子元素添加到 <customBinding>,指定发送到此服务以及从此服务发送出去的消息的身份验证模式。
通过将
authenticationMode
属性设置为SecureConversation
,指定使用安全会话。 通过将requireSecurityContextCancellation
属性设置为false
,指定使用有状态 SCT。<security authenticationMode="SecureConversation" requireSecurityContextCancellation="false"> </security>
通过将一个 <secureConversationBootstrap> 子元素添加到 <security>,指定在建立安全会话时如何对客户端进行身份验证。
通过设置
authenticationMode
属性,指定如何对客户端进行身份验证。<secureConversationBootstrap authenticationMode="UserNameForCertificate" />
指定消息编码,方法是添加一个编码元素,例如 <textMessageEncoding>。
<textMessageEncoding />
指定传输,方法是添加一个传输元素,例如 <httpTransport>。
<httpTransport />
下面的代码示例使用配置来指定一个自定义绑定,消息可以将该绑定与安全会话中的有状态 SCT 结合使用。
<customBinding> <binding name="StatefulSCTSecureSession"> <security authenticationMode="SecureConversation" requireSecurityContextCancellation="false"> <secureConversationBootstrap authenticationMode="UserNameForCertificate" /> </security> <textMessageEncoding /> <httpTransport /> </binding> </customBinding>
示例
下面的代码示例创建一个自定义绑定,该绑定使用 MutualCertificate 身份验证模式启动安全会话。
SecurityBindingElement security = SecurityBindingElement.CreateMutualCertificateBindingElement();
// Use a secure session and specify that stateful SecurityContextToken security tokens are used.
security = SecurityBindingElement.CreateSecureConversationBindingElement(security, false);
// Specify whether derived keys are needed.
security.SetKeyDerivation(true);
// Create the custom binding.
CustomBinding myBinding = new CustomBinding(security, new HttpTransportBindingElement());
// Create the Type instances for later use and the Uri for
// the base address.
Type contractType = typeof(ICalculator);
Type serviceType = typeof(Calculator);
Uri baseAddress = new
Uri("http://localhost:8036/serviceModelSamples/");
// Create the ServiceHost and add an endpoint, then start
// the service.
ServiceHost myServiceHost =
new ServiceHost(serviceType, baseAddress);
myServiceHost.AddServiceEndpoint
(contractType, myBinding, "secureCalculator");
myServiceHost.Open();
Dim security As SecurityBindingElement = SecurityBindingElement.CreateMutualCertificateBindingElement()
' Use a secure session and specify that stateful SecurityContextToken security tokens are used.
security = SecurityBindingElement.CreateSecureConversationBindingElement(security, False)
' Specify whether derived keys are needed.
security.SetKeyDerivation(True)
' Create the custom binding.
Dim myBinding As New CustomBinding(security, New HttpTransportBindingElement())
' Create the Type instances for later use and the Uri for
' the base address.
Dim contractType As Type = GetType(ICalculator)
Dim serviceType As Type = GetType(Calculator)
Dim baseAddress As New Uri("http://localhost:8036/serviceModelSamples/")
' Create the ServiceHost and add an endpoint, then start
' the service.
Dim myServiceHost As New ServiceHost(serviceType, baseAddress)
myServiceHost.AddServiceEndpoint(contractType, myBinding, "secureCalculator")
myServiceHost.Open()
在将 Windows 身份验证与有状态 SCT 结合使用时,WCF 不使用实际调用方的标识来填充 WindowsIdentity 属性,而是将该属性设置为匿名。 由于 WCF 安全性必须为来自传入 SCT 的每个请求重新创建服务安全性上下文的内容,因此服务器不会跟踪内存中的安全会话。 因为不可能将 WindowsIdentity 实例序列化为 SCT,所以 WindowsIdentity 属性返回一个匿名标识。
下面的配置演示这一行为。
<customBinding>
<binding name="Cancellation">
<textMessageEncoding />
<security
requireSecurityContextCancellation="false">
<secureConversationBootstrap />
</security>
<httpTransport />
</binding>
</customBinding>