English 中文(简体)
How would you implement API key in WCF Data Service?
原标题:

Is there a way to require an API key in the URL / or some other way of passing the service a private key in order to grant access to the data?

I have this 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);
    }
} 

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

最佳回答

I would suggest using the authorization header to pass the apiKey instead of passing it in the query string. That s what it is there for and it help s to keep api keys out of log files.

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

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

instead of searching the entire uri string, if it makes it feel less icky!

问题回答

Looks like the technique presented in this video works well even in WCF Data Services. You create a custom subclass of ServiceAuthorizationManager (see MSDN), override CheckAccessCore(), and register it in web.config.

I got it to work by passing a key in a HTTP header of the request. The OperationContext passed to CheckAccessCore doesn t give you a way to grab the HTTP Request headers, but you can get them via HttpContext.Current.Request.Headers. You can then get the proper header out of that collection and check it however you need to.

Here is the necessary registration in 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.

UPDATE 2: HttpContext.Current is only null when you re not running WCF in ASP.NET Compatibility mode. You can turn this on by adding the following line to web.config at the application level in the system.serviceModel node:

<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>

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

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]

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

You can check the request type and let wsdl calls go through with out the api key.

I am not sure what your api goals are but you could use a client certificate.





相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签