【问题标题】:Adding and Retrieving data from request context从请求上下文中添加和检索数据
【发布时间】:2011-12-02 00:13:24
【问题描述】:

我正在尝试将 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 标头。谁能看出我哪里出错了?

【问题讨论】:

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


    【解决方案1】:

    您可以通过这种方式添加自定义标题:

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

    【讨论】:

    • 谢谢!我发现我遇到的问题是因为我没有在上下文范围的生命周期内进行服务调用!
    • 什么是服务渠道? IMyServiceChannel?
    • IMyServiceChannel 是客户端和服务器之间的通信通道接口。
    • IMyServiceChannel的定义在哪里?
    【解决方案2】:

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

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

    下面的 sn-p 应该足以让您入门。您可能必须将 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);
    
            ...
    

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 是的,我看过了,我想尝试保留服务身份验证管理器,因为它正是我需要的。
      猜你喜欢
      • 2021-10-17
      • 2017-06-16
      • 1970-01-01
      • 2013-03-03
      • 2019-06-26
      • 2022-10-06
      • 2021-10-06
      • 2020-01-09
      • 1970-01-01
      相关资源
      最近更新 更多