从请求上下文添加和检索数据

时间:2011-10-06 05:48:24

标签: c# wcf asp.net-mvc-3

我正在尝试将api密钥附加到OperationContext传出邮件头,如下所示:

    public static void AddApikeyToHeader(string apikey, IContextChannel channel, string address)
    {
        using (OperationContextScope scope = new OperationContextScope(channel))
        {
            MessageHeader header = MessageHeader.CreateHeader("apikey", address, apikey);
            OperationContext.Current.OutgoingMessageHeaders.Add(header);

        }
    }

但后来我不知道如何在服务器端检索标头。我正在使用服务授权管理器,我得到当前的操作上下文并尝试检索这样的标题:

    public string GetApiKey(OperationContext operationContext)
    {
        var request = operationContext.RequestContext.RequestMessage;

        var prop = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name];

        return prop.Headers["apikey"];
    }

但那里没有apikey标题。另外,在我检查operationContext的时候调试我似乎无法在任何地方看到我的apikey头。谁能看到我哪里出错?

3 个答案:

答案 0 :(得分:14)

您可以通过以下方式添加自定义标头:

using (ChannelFactory<IMyServiceChannel> factory = 
       new ChannelFactory<IMyServiceChannel>(new NetTcpBinding()))
      {
       using (IMyServiceChannel proxy = factory.CreateChannel(...))
       {
          using ( OperationContextScope scope = new OperationContextScope(proxy) )
          {
             Guid apiKey = Guid.NewGuid();
             MessageHeader<Guid> mhg = new MessageHeader<Guid>(apiKey);
             MessageHeader untyped = mhg.GetUntypedHeader("apiKey", "ns");
             OperationContext.Current.OutgoingMessageHeaders.Add(untyped);

             proxy.DoOperation(...);
          }
       }                    
    }

在服务方面,您可以获得如下标题:

Guid apiKey = 
OperationContext.Current.IncomingMessageHeaders.GetHeader<Guid>("apiKey", "ns");

答案 1 :(得分:1)

我假设您尝试使用基于Http协议的传输(SOAP,REST等)来使用您的服务。我还假设你想要的是使用提供的API密钥授权调用者。如果这两个条件都适用于您的问题,您可以继续阅读。

我最近不得不解决类似的问题,只是我没有传递API密钥,而是使用一些HTTP自定义标头的用户名/密码哈希组合。我最终通过实现一个自定义授权策略解决了这个问题,该策略曾经在Web.config中配置好,很好地挂钩到WCF管道。

下面的代码段应该足以让您入门。您可能需要将x-ms-credentials-XXX标头替换为代表您的API密钥的单个标头。

internal class RESTAuthorizationPolicy : IAuthorizationPolicy
{
  public RESTAuthorizationPolicy()
  {
    Id = Guid.NewGuid().ToString();
    Issuer = ClaimSet.System;
  }

  public bool Evaluate(EvaluationContext evaluationContext, ref object state)
  {
    const String HttpRequestKey = "httpRequest";
    const String UsernameHeaderKey = "x-ms-credentials-username";
    const String PasswordHeaderKey = "x-ms-credentials-password";
    const String IdentitiesKey = "Identities";
    const String PrincipalKey = "Principal";

    // Check if the properties of the context has the identities list 
    if (evaluationContext.Properties.Count > 0 ||
      evaluationContext.Properties.ContainsKey(IdentitiesKey) ||
      !OperationContext.Current.IncomingMessageProperties.ContainsKey(HttpRequestKey))
      return false;

    // get http request
    var httpRequest = (HttpRequestMessageProperty)OperationContext.Current.IncomingMessageProperties[HttpRequestKey];

    // extract credentials
    var username = httpRequest.Headers[UsernameHeaderKey];
    var password = httpRequest.Headers[PasswordHeaderKey];

    // verify credentials complete
    if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
      return false;

    // Get or create the identities list 
    if (!evaluationContext.Properties.ContainsKey(IdentitiesKey))
      evaluationContext.Properties[IdentitiesKey] = new List<IIdentity>();
    var identities = (List<IIdentity>) evaluationContext.Properties[IdentitiesKey];

    // lookup user
    using (var con = ServiceLocator.Current.GetInstance<IDbConnection>())
    {
      using (var userDao = ServiceLocator.Current.GetDao<IUserDao>(con))
      {
        var user = userDao.GetUserByUsernamePassword(username, password);

        ...

答案 2 :(得分:0)

您是否看过这个问题:How to add a custom HTTP header to every WCF call??它可能包含您的解决方案。