How to implement an API key in a WCF data service?

Is there a way to get the API key in the URL / or some other way to pass the private key service to provide data access?

I have it right now ...

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

... It works, but it is not ideal, because you cannot get into the metadata and discover the service through the Add Service Reference explorer. I could check if there is $ metadata in the url, but that seems like a hack. Is there a better way?

+4
source share
3 answers

I would suggest using an authorization header to pass apiKey instead of passing it in the query string. This is what it is for and helps to save api keys from log files.

I don't think there is anything really wrong with checking for the presence of "$ metadata" in the url. You write the code on the server side, and the server owns the URI space, so making decisions based on the text in the request URL is what the server is. You can use something like

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

instead of looking for the entire uri string if it makes her feel less icky!

+5
source

It seems that the technique presented in this video works well even in WCF data services. You create your own subclass of ServiceAuthorizationManager (see MSDN ), override CheckAccessCore() and register it in web.config.

I got it to work by passing the key in the HTTP request header. OperationContext passed to CheckAccessCore you from capturing the headers of the HTTP request , but you can get them through HttpContext.Current.Request.Headers . Then you can get the correct title from this collection and check it out, but you need to.

Here is the required registration in web.config:

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

UPDATE: I was wrong in getting the headers from HttpContext.Current.Request.Headers ; HttpContext.Current is null when working in IIS (but interestingly not when debugging). Instead, use WebOperationContext.Current.IncomingRequest.Headers in accordance with this question .

UPDATE 2: HttpContext.Current is null if you are not using WCF in ASP.NET compatibility mode. You can enable this by adding the following line to the application-level web.config in the system.serviceModel node:

 <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/> 

Also add this above to your service implementation if you have a vanilla WCF service that works in addition to the ADO.NET service:

 [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)] 

Then you can get HttpContext.Current.Request.Headers and all the other things provided by the HttpRequest .

+1
source

You can check the type of request and allow wsdl calls using the api key.

I'm not sure what your api goals are, but you can use a client certificate.

0
source

Source: https://habr.com/ru/post/1304635/


All Articles