Как бы вы реализовали ключ API в службе данных WCF?

Есть ли способ потребовать ключ 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);
    }
} 

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


person Rush Frisby    schedule 20.03.2010    source источник
comment
Будет ли это работать с механизмами кэширования, описанными здесь: hanselman.com/blog/   -  person friism    schedule 05.09.2010


Ответы (3)


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

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

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

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

person Darrel Miller    schedule 20.03.2010
comment
Я получил аналогичный ответ на форумах MSDN. Не могу поверить, что нет лучшего способа. Это похоже на взлом, но, похоже, мне придется пойти по этому пути. Спасибо. - person Rush Frisby; 20.03.2010

Похоже на метод, представленный в это видео хорошо работает даже в WCF Data Services. Вы создаете собственный подкласс 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>

UPDATE: I was wrong about being able to get headers out of HttpContext.Current.Request.Headers; HttpContext.Current is null when running in IIS (but interestingly not when debugging). Instead, use WebOperationContext.Current.IncomingRequest.Headers as per this question.

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

<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>

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

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]

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

person Tom Hamming    schedule 30.05.2012
comment
Проблема здесь в том, что ошибки возвращаются в виде XML во всех случаях, независимо от того, какой формат запросил клиент. - person Monstieur; 20.02.2013

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

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

person Aaron Fischer    schedule 20.03.2010
comment
Что вы подразумеваете под типом запроса? Конечная точка $metadata — это не WSDL, а CSDL, не так ли? - person Darrel Miller; 20.03.2010