Как бы вы реализовали API-ключ в службе данных WCF? - PullRequest
4 голосов
/ 20 марта 2010

Есть ли способ потребовать ключ API в URL-адресе / или какой-либо другой способ передать службе закрытый ключ для предоставления доступа к данным?

У меня есть это прямо сейчас ...

using System;
using System.Data.Services;
using System.Data.Services.Common;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.Web;
using Numina.Framework;
using System.Web;
using System.Configuration;

[System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class odata : DataService {


    public static void InitializeService(DataServiceConfiguration config) {

        config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
        //config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
        config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
    }

    protected override void OnStartProcessingRequest(ProcessRequestArgs args) {

        HttpRequest Request = HttpContext.Current.Request;
        if(Request["apikey"] != ConfigurationManager.AppSettings["ApiKey"])
            throw new DataServiceException("ApiKey needed");

        base.OnStartProcessingRequest(args);
    }
} 

... Это работает, но не идеально, потому что вы не можете получить метаданные и обнаружить службу через проводник Add Service Reference. Я мог бы проверить, есть ли $ метаданные в URL, но это похоже на хак. Есть ли лучший способ?

Ответы [ 3 ]

5 голосов
/ 20 марта 2010

Я бы предложил использовать заголовок авторизации для передачи apiKey вместо того, чтобы передавать его в строке запроса. Вот для чего это нужно, и это помогает сохранить ключи API в файлах журналов.

Я не думаю, что действительно что-то не так с проверкой на наличие '$ metadata' в URL. Вы пишете код на стороне сервера, а серверу принадлежит пространство URI, поэтому сервер принимает решения на основе текста в URL-адресе запроса. Вы могли бы использовать что-то вроде

  if (requestUrl.Segments.Last().Replace('/','') != '$metadata') 

вместо поиска по всей строке uri, если это заставляет ее чувствовать себя менее неприлично!

1 голос
/ 31 мая 2012

Похоже, техника, представленная в , это видео хорошо работает даже в службах данных WCF. Вы создаете пользовательский подкласс ServiceAuthorizationManager (см. MSDN ), переопределяете CheckAccessCore() и регистрируете его в web.config.

Я заставил его работать, передав ключ в заголовке HTTP запроса. OperationContext, переданный CheckAccessCore, не дает возможности получить заголовки HTTP-запроса , но вы можете получить их через HttpContext.Current.Request.Headers. Затем вы можете получить правильный заголовок из этой коллекции и проверить его так, как вам нужно.

Вот необходимая регистрация в web.config:

<system.serviceModel>
  <behaviors>
      <serviceBehaviors>
          <behavior>
              <serviceAuthorization serviceAuthorizationManagerType="FullyQualifiedTypeNameHere, ProjectNameHere" />
          </behavior>
      </serviceBehaviors>
  </behaviors>

ОБНОВЛЕНИЕ: Я был не прав, имея возможность получить заголовки из HttpContext.Current.Request.Headers; HttpContext.Current равно нулю при работе в IIS (но, что интересно, не при отладке). Вместо этого используйте WebOperationContext.Current.IncomingRequest.Headers согласно этому вопросу .

ОБНОВЛЕНИЕ 2: HttpContext.Current является нулевым, только если вы не используете WCF в режиме совместимости с ASP.NET. Вы можете включить это, добавив следующую строку в web.config на уровне приложения в узле system.serviceModel:

<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>

Также добавьте это выше реализации вашей службы, если у вас есть ванильная служба WCF, работающая в дополнение к службе ADO.NET:

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]

Тогда вы можете получить HttpContext.Current.Request.Headers и все остальные вещи, предоставляемые классом HttpRequest.

0 голосов
/ 20 марта 2010

Вы можете проверить тип запроса и разрешить вызовы wsdl без использования ключа API.

Я не уверен, каковы ваши цели API, но вы можете использовать сертификат клиента.

...