C# 处理WCF标头详细信息
我正在为一些STS服务构建一个客户机,现在有一天多的时间我在尝试向WCF消息添加一个头。在对RequestSecurityToken的调用中,我必须包含一个UsernameTokenC# 处理WCF标头详细信息,c#,wcf,security,header,C#,Wcf,Security,Header,我正在为一些STS服务构建一个客户机,现在有一天多的时间我在尝试向WCF消息添加一个头。在对RequestSecurityToken的调用中,我必须包含一个UsernameToken public class MessageInspector : IClientMessageInspector { public object BeforeSendRequest(ref Message request, IClientChannel channel) { Security uns =
public class MessageInspector : IClientMessageInspector {
public object BeforeSendRequest(ref Message request, IClientChannel channel) {
Security uns = new Security();
uns.UsernameToken = new UsernameToken();
// ...
var Header = new MessageHeader<Security>(uns);
var untyped = Header.GetUntypedHeader("Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
request.Headers.Add(untyped);
return null;
}
}
public class Security : MessageHeader {
public UsernameToken UsernameToken = new UsernameToken();
public override string Name {
get { return "Security"; }
}
public override string Namespace {
get { return "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; }
}
}
public class UsernameToken {
public String Username = "";
public Password Password = new Password();
}
我不知道如何做到这一点。目前,我定义了一个端点行为和一个消息检查器(花了我足够长的时间来发现它们…)。在后者的BeforeSendRequest()中,我创建了一个自定义类“Security”的对象,该类派生自MessageHeader。安全性包括UsernameToken的一个实例
public class MessageInspector : IClientMessageInspector {
public object BeforeSendRequest(ref Message request, IClientChannel channel) {
Security uns = new Security();
uns.UsernameToken = new UsernameToken();
// ...
var Header = new MessageHeader<Security>(uns);
var untyped = Header.GetUntypedHeader("Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
request.Headers.Add(untyped);
return null;
}
}
public class Security : MessageHeader {
public UsernameToken UsernameToken = new UsernameToken();
public override string Name {
get { return "Security"; }
}
public override string Namespace {
get { return "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; }
}
}
public class UsernameToken {
public String Username = "";
public Password Password = new Password();
}
公共类消息检查器:IClientMessageInspector{
发送请求前的公共对象(参考消息请求,IClientChannel通道){
安全uns=新安全();
uns.UsernameToken=新的UsernameToken();
// ...
var Header=新消息头(uns);
var untyped=Header.GetUntypedHeader(“安全性”)http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
request.Headers.Add(非类型化);
返回null;
}
}
公共类安全性:MessageHeader{
public UsernameToken UsernameToken=new UsernameToken();
公共重写字符串名{
获取{return“Security”;}
}
公共重写字符串命名空间{
获取{return“http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; }
}
}
公共类UsernameToken{
公共字符串用户名=”;
公共密码=新密码();
}
这就是正在连载的内容
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">urn:RequestSecurityToken</Action>
<Security xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<UsernameToken xmlns="http://schemas.datacontract.org/2004/07/Tarifrechner.Kfz">
<Password>
<Type>http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText</Type>
<password>******</password>
</Password>
<Username>******</Username>
</UsernameToken>
</Security>
</s:Header>
<s:Body />
</s:Envelope>
urn:RequestSecurityToken
http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText
******
******
尤其是UsernameToken的名称空间似乎是错误的。我知道它来自数据协定序列化,但我需要一个不同的名称空间
这就是我希望序列化数据的样子
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="...">
<soap:Header>
<Security xmlns:q1="http://www.bipro.net/namespace" xsi:type="q1:UserNameSecurity"
xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<UsernameToken>
<Username>******</Username>
<Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">******</Password>
</UsernameToken>
</Security>
<wsa:Action>urn:RequestSecurityToken</wsa:Action>
<wsse:Security>
<wsu:Timestamp wsu:Id="Timestamp-b9dd599d-5901-451d-8321-6a309091f273">
<wsu:Created>2012-03-11T16:02:56Z</wsu:Created>
<wsu:Expires>2012-03-11T16:07:56Z</wsu:Expires>
</wsu:Timestamp>
</wsse:Security>
</soap:Header>
<soap:Body>
<RequestSecurityToken xmlns="http://schemas.xmlsoap.org/ws/2005/02/trust">
<TokenType>http://schemas.xmlsoap.org/ws/2005/02/sc/sct</TokenType>
<RequestType>
http://schemas.xmlsoap.org/ws/2005/02/trust/Issue
</RequestType>
</RequestSecurityToken>
</soap:Body>
</soap:Envelope>
******
******
urn:RequestSecurityToken
2012-03-11T16:02:56Z
2012-03-11T16:07:56Z
http://schemas.xmlsoap.org/ws/2005/02/sc/sct
http://schemas.xmlsoap.org/ws/2005/02/trust/Issue
我的方法正确吗?我如何处理诸如标题细节的名称空间或数据是否被序列化为属性或元素之类的事情
更新
正如Ladislav已经指出的,我自己不必实现像UsernameToken这样的类。我这样做只是因为我对WCF的了解非常有限 到目前为止,我发现,WS2007HttpBinding配置为使用SecurityMode.TransportWithMessageCredential,并将EstablishSecurityContext设置为false,生成的几乎就是我要查找的XML。我怎么会知道呢 但还有一个问题:我的请求有一个空的body元素,我要生成的请求在body元素中有一个RequestSecurityToken元素。有谁知道,我怎样才能做到这一点 使用EstablishSecurityContext=true会有所帮助,但同时会将我的Soap操作从所需的“urn:RequestSecurityToken”更改为非工作状态http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/SCT“
谢谢你的回答 非常感谢
Björn根据您需要如何控制标题内容以及需要在何处插入标题,有几种不同的方法向消息添加标题 在应用程序代码中,可以围绕请求创建OperationContextScope,以更改某些请求属性。在OperationContextScope中,您拥有OperationContext.Current的有效实例,该实例允许通过OutgoingMessageHeaders集合操纵消息头。此方法的使用将头的控制深度烘焙到应用程序代码中。您必须负责在需要的地方复制适当的代码
链接(来自WCF团队中的某个人)通过大量代码示例更详细地讨论了这一点:另一种方法是为您的请求定义MessageContract类型,它允许您定义SOAP消息头和消息体中显示的内容,并调整使用的命名空间。例如,考虑以下服务定义:
[ServiceContract]
public interface IMyService
{
[OperationContract]
MyResponse DoSomething(MyRequest request);
}
public class MyService : IMyService
{
public MyResponse DoSomething(MyRequest request)
{
return new MyResponse()
{
Details = "Service did something awesome.",
Timestamp = DateTime.Now
};
}
}
[MessageContract(IsWrapped = true, WrapperNamespace = "http://myservice/messages/")]
public class MyRequest
{
[MessageHeader(Namespace = "http://myservice/security")]
public string TokenThingy
{
get;
set;
}
}
[MessageContract(IsWrapped = true, WrapperNamespace = "http://myservice/messages")]
public class MyResponse
{
[MessageBodyMember]
public string Details
{
get;
set;
}
[MessageBodyMember]
public DateTime Timestamp
{
get;
set;
}
}
发送请求会产生以下SOAP:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/IMyService/DoSomething</Action>
<h:TokenThingy xmlns:h="http://myservice/security">fda</h:TokenThingy>
</s:Header>
<s:Body>
<MyRequest xmlns="http://myservice/messages/" />
</s:Body>
</s:Envelope>
http://tempuri.org/IMyService/DoSomething
食品和药物管理局
服务的响应如下所示:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header />
<s:Body>
<MyResponse xmlns="http://myservice/messages">
<Details xmlns="http://tempuri.org/">Service did something awesome.</Details>
<Timestamp xmlns="http://tempuri.org/">2012-05-04T17:04:36.5980424-04:00</Timestamp>
</MyResponse>
</s:Body>
</s:Envelope>
服务做了一些很棒的事情。
2012-05-04T17:04:36.5980424-04:00
希望这会有所帮助为什么要手动执行此操作?如果您设置WCF安全配置,它将为您添加这些头。