我希望这可以帮助别人。我将 SoapCore 1.1.0.28 与 .Net Core 6 一起使用。我尝试了 @wolfyuk 列出的 Tune 方法,但 Core 总是将字节返回为 null,因此我永远无法通过 null 检查。
我发现最直接的方法是使用 SoapCore 中的 IMessageInspector2 创建中间件来拦截传入的 SOAP 请求并拦截传出的 SOAP 响应。实现 IMessageInspector2 的类可以访问该消息,因此您可以在进入时提取标头(这就是我需要的),并在退出时添加标头。我需要将请求标头包含在我的响应中(我正在通信的系统的要求)。
public class AuthMessageFilter : IMessageInspector2
{
private const string WsNamespaceSecurityUri = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
private const string WsUserNameTokenNodeName = "UsernameToken";
private const string WsSecurityNodeName = "Security";
private const string WsTimestampNodeName = "Timestamp";
private readonly IMyService _service;
private readonly IHttpContextAccessor _acc;
private readonly ILogger _logger;
private MessageHeaders _messageHeaders;
public AuthMessageFilter(IHttpContextAccessor acc, IMyService service, ILogger logger)
{
_acc = acc;
_service = service;
_logger = logger;
}
public object AfterReceiveRequest(ref Message message, ServiceDescription serviceDescription)
{
ValidateSoapAction();
var token = GetUserNameToken(message);
var userIsAuthenticated = _service.ValidateUser(token.Username, token.Password.Value).GetAwaiter().GetResult();
if (userIsAuthenticated)
{
_messageHeaders = message.Headers; // use in response.
return null;
}
const string msg = "The user credentials did not authenticate.";
_logger.LogEntry(msg);
throw new AuthenticationFailedException(msg);
}
private void ValidateSoapAction()
{
try
{
var soapAction = _acc.HttpContext?.Request.Headers["SOAPAction"].FirstOrDefault()?.Replace("\"", "");
if (soapAction == null)
{
throw new Exception(
"Error: Could not extract SoapAction from HttpContext.Request.Headers. Aborting SOAP operation.");
}
}
catch (Exception ex)
{
_logger.LogEntry("No SOAP Action found.", ex);
}
}
private WsUsernameToken GetUserNameToken(Message message)
{
WsUsernameToken wsUsernameToken = null;
for (var i = 0; i < _messageHeaders.Count; i++)
{
if (!_messageHeaders[i].Name.Equals(WsSecurityNodeName, StringComparison.OrdinalIgnoreCase))
continue;
using var reader = _messageHeaders.GetReaderAtHeader(i);
while (reader.Read())
{
if (reader.IsStartElement() &&
reader.NamespaceURI.Equals(WsNamespaceSecurityUri, StringComparison.OrdinalIgnoreCase) &&
reader.LocalName.Equals(WsUserNameTokenNodeName, StringComparison.OrdinalIgnoreCase))
{
var serializer = new XmlSerializer(typeof(WsUsernameToken));
wsUsernameToken = (WsUsernameToken)serializer.Deserialize(reader);
break;
}
}
break;
}
if (wsUsernameToken == null)
{
var ex = new SecurityException("An exception occurred when verifying security for the message.");
_logger.LogEntry(LoggingCategory.Service, LoggingLevel.Error, ex.Message, ex);
throw ex;
}
return wsUsernameToken;
}
public void BeforeSendReply(ref Message reply, ServiceDescription serviceDescription, object correlationState)
{
for (var i = 0; i < _messageHeaders.Count; i++)
{
if (!_messageHeaders[i].Name.Equals(WsSecurityNodeName, StringComparison.OrdinalIgnoreCase))
continue;
using var reader = _messageHeaders.GetReaderAtHeader(i);
while (reader.Read())
{
if (reader.IsStartElement() &&
reader.NamespaceURI.Equals(WsNamespaceSecurityUri, StringComparison.OrdinalIgnoreCase) &&
reader.LocalName.Equals(WsTimestampNodeName, StringComparison.OrdinalIgnoreCase))
{
reply.Headers.Add(_messageHeaders[i] as MessageHeader);
break;
}
}
break;
}
}
}