我有一个使用WSHttpBinding的自托管soap服务器。除了一些操作,它还提供了一个通用的合同接口:
[ServiceContract(Namespace = "http://myns")]
public interface IGenericService
{
[OperationContract]
string GetData(int value);
[OperationContract(Action = "*", ReplyAction = "*")]
Message ProcessMessage(Message message);
}
主持人应使用自己的UserNamePasswordValidator。我这样设置:
ServiceCredentials servCredBehav = new ServiceCredentials();
servCredBehav.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
servCredBehav.UserNameAuthentication.CustomUserNamePasswordValidator = new MyUserNamePasswordValidator();
host.Description.Behaviors.Add(servCredBehav);
WSHttpBinding binding = new WSHttpBinding(SecurityMode.TransportWithMessageCredential);
binding.Name = "WS_SOAP_12";
...
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
这是(已清理过的)验证器:
public class MyUserNamePasswordValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (userName != "test" && password != "test123")
throw new SecurityTokenException("Invalid user name or incorrect password");
}
}
当我使用visual studio创建代理并调用GetData时,这很好用:
using (GenericService12Https.GenericServiceClient bla = new GenericService12Https.GenericServiceClient())
{
bla.ClientCredentials.UserName.UserName = "test";
bla.ClientCredentials.UserName.Password = "test123";
bla.Open();
string s = bla.GetData(5);
}
当我使用HttpWebRequest等低级方法访问此soap服务并直接向其发送xml以便调用ProcessMessage()时,会出现问题。
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Security soap:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken wsu:Id="uuid-412594ae-2641-4b2f-8458-631e17940108-1">
<wsse:Username>test</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">test123</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
<wsa:MessageID>...</wsa:MessageID>
<wsa:To>https://localhost:44301/Receiver.svc</wsa:To>
<wsa:Action>...</wsa:Action>
</soap:Header>
<soap:Body>
<Dummy/>
</soap:Body>
</soap:Envelope>
服务器返回包含该内容的HTTP 500错误(原始错误,德语,通过谷歌翻译):
无法处理邮件。可能的原因:行动&#34; ... &#34;如果错误,则邮件包含无效或过期的安全性 上下文令牌或债券之间是冲突。安全上下文 如果服务具有该通道,则令牌将无效 由于不活动而终止。增加的接收超时 绑定服务端点以防止服务终止空闲 会议过早。
要么我用
binding.Security.Message.ClientCredentialType = MessageCredentialType.None;
然后我可以在ProcessMessage()中手动检查凭据,但可以未经授权访问GetData()或
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
这样GetData()按预期工作,但从不调用ProcessMessage()。
有关如何为所有操作和通用合同启用用户名/密码验证的任何建议? 顺便说一句。我不能改变xml标题,因为它们来自外国系统。