在WCF SOAP API使用HTTP授权头认证 [英] Authentication using HTTP Authorization Header in WCF SOAP API
问题描述
我们目前有一个WCF SOAP API,允许消费者使用一个用户名和密码进行身份验证(内部使用的 UserNamePasswordValidator )作为参考的用户名和密码,在SOAP体传递如下:
We currently have a WCF SOAP API that allows the consumer to authenticate using a username and password (internally uses a UserNamePasswordValidator) For reference the username and password is passed in the SOAP Body as follows:
<o:Security xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" mustUnderstand="1">
<Timestamp Id="_0">
<Created>
2013-04-05T16:35:07.341Z</Created>
<Expires>2013-04-05T16:40:07.341Z</Expires>
</Timestamp>
<o:UsernameToken Id="uuid-ac5ffd20-8137-4524-8ea9-3f4f55c0274c-12">
<o:Username>someusername</o:Username>
<o:Password o:Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">somepassword
</o:Password>
</o:UsernameToken>
</o:Security>
我们大家喜欢的此外支持用户在指定凭据< A HREF =http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.8相对=nofollow> HTTP授权头,因为无论是基本身份验证,或< A HREF =http://tools.ietf.org/html/draft-ietf-oauth-v2-bearer-15#section-2.1相对=nofollow> OAuth的承载令牌
We we like to additionally support a consumer to specify credentials in the HTTP Authorization header, as either Basic auth, or an OAuth Bearer token
我们已经有了实际做非SOAP的API认证几种方法,但我不熟悉如何告诉WCF使用我可能会为此创造任何类。我怎样才能做到这一点?我见过的唯一的其他问题,试图回答这个是这里,但接受答使用SOAP头,而不是HTTP头,和提问者基本上放弃了
We already have several ways of actually doing the authentication for non-SOAP APIs, but I am not familiar with how to tell WCF to use any class I might create for this. How can I accomplish this? The only other question I have seen that attempts to answer this is here, but the accepted answer uses SOAP headers, not HTTP headers, and the asker essentially gave up.
显然,任何解决方案需要向后兼容 - 我们需要继续支持消费者指定凭据。在SOAP安全标
Obviously any solution needs to be backwards compatible - we need to continue to support consumers specifying credentials in the SOAP Security Header.
推荐答案
一个可以使用的 MessageInspectors 的。
事情是这样的:
One of the ways you can go is using MessageInspectors.
Something like this:
的首页的 - 创建消息检查 - 负责与您的凭据加头p>
First - create message inspector - to be responsible to add header with your credentials
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;
using System.ServiceModel;
using System.Xml;
namespace your_namespace
{
/// <summary>
/// /************************************
/// *
/// * Creating Message inspector for
/// * updating all outgoing messages with Caller identifier header
/// * read http://msdn.microsoft.com/en-us/magazine/cc163302.aspx
/// * for more details
/// *
/// *********************/
/// </summary>
public class CredentialsMessageInspector : IDispatchMessageInspector,
IClientMessageInspector
{
public object AfterReceiveRequest(ref Message request,
IClientChannel channel,
InstanceContext instanceContext)
{
return null;
}
public void BeforeSendReply(ref Message reply, object
correlationState)
{
#if DEBUG
//// Leave empty
//MessageBuffer buffer = reply.CreateBufferedCopy(Int32.MaxValue);
//Message message = buffer.CreateMessage();
////Assign a copy to the ref received
//reply = buffer.CreateMessage();
//StringWriter stringWriter = new StringWriter();
//XmlTextWriter xmlTextWriter = new XmlTextWriter(stringWriter);
//message.WriteMessage(xmlTextWriter);
//xmlTextWriter.Flush();
//xmlTextWriter.Close();
//String messageContent = stringWriter.ToString();
#endif
}
public void AfterReceiveReply(ref Message reply, object
correlationState)
{
#if DEBUG
//// Leave empty
//MessageBuffer buffer = reply.CreateBufferedCopy(Int32.MaxValue);
//Message message = buffer.CreateMessage();
////Assign a copy to the ref received
//reply = buffer.CreateMessage();
//StringWriter stringWriter = new StringWriter();
//XmlTextWriter xmlTextWriter = new XmlTextWriter(stringWriter);
//message.WriteMessage(xmlTextWriter);
//xmlTextWriter.Flush();
//xmlTextWriter.Close();
//String messageContent = stringWriter.ToString();
#endif
}
public object BeforeSendRequest(ref Message request,
IClientChannel channel)
{
request = CredentialsHelper.AddCredentialsHeader(ref request);
return null;
}
#region IDispatchMessageInspector Members
#endregion
}
}
的二的 - 添加代码,添加标题
Second - add the code to add header
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.ServiceModel.Channels;
using System.ServiceModel;
namespace your_namespace
{
public class CredentialsHelper
{
// siple string is for example - you can use your data structure here
private static readonly string CredentialsHeaderName = "MyCredentials";
private static readonly string CredentialsHeaderNamespace = "urn:Urn_probably_like_your_namespance";
/// <summary>
/// Update message with credentials
/// </summary>
public static Message AddCredentialsHeader(ref Message request)
{
string user = "John";
string password = "Doe";
string cred = string.Format("{0},{1}", user, password);
// Add header
MessageHeader<string> header = new MessageHeader<string>(cred);
MessageHeader untyped = header.GetUntypedHeader(CredentialsHeaderName, CredentialsHeaderNamespace);
request = request.CreateBufferedCopy(int.MaxValue).CreateMessage();
request.Headers.Add(untyped);
return request;
}
/// <summary>
/// Get details of current credentials from client-side added incoming headers
///
/// Return empty credentials when empty credentials specified
/// or when exception was occurred
/// </summary>
public static string GetCredentials()
{
string credentialDetails = string.Empty;
try
{
credentialDetails = OperationContext.Current.IncomingMessageHeaders.
GetHeader<string>
(CredentialsHeaderName, CredentialsHeaderNamespace);
}
catch
{
// TODO: ...
}
return credentialDetails;
}
}
}
第三的 - 让你的服务器端
Third - get your credentials on the server side
public void MyServerSideMethod()
{
string credentials = CredentialsHelper.GetCredentials();
. . .
}
希望这有助于。
Hope this helps.
这篇关于在WCF SOAP API使用HTTP授权头认证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!