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

5

我正在尝试将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个回答

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(...);
          }
       }                    
    }

在服务端,您可以获取标题(header)如下:

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

谢谢!我发现我遇到的问题是因为我没有在上下文范围的生命周期内进行服务调用! - Dimitar
什么是服务通道?IMyServiceChannel是什么? - PositiveGuy
IMyServiceChannel是客户端和服务器之间的通信通道接口。 - Upendra Chaudhari
IMyServiceChannel 的定义在哪里? - Chris Pickford

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);

        ...

0

是的,我看了一下,我想尝试保留服务认证管理器,因为它正是我所需要的。 - Dimitar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接