如何在 WCF 数据服务中实现 API 密钥?

发布于 2024-08-26 02:19:25 字数 1204 浏览 2 评论 0原文

有没有办法要求 URL 中包含 API 密钥/或通过其他方式向服务传递私钥以授予对数据的访问权限?

我现在有这个...

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

...这可以工作,但并不完美,因为您无法通过“添加服务引用”资源管理器获取元数据并发现服务。我可以检查 $metadata 是否在 url 中,但这看起来像是一个 hack。有更好的办法吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

冬天旳寂寞 2024-09-02 02:19:25

我建议使用授权标头来传递 apiKey,而不是在查询字符串中传递它。这就是它的用途,它有助于将 api 密钥排除在日志文件之外。

我不认为检查 url 中是否存在“$metadata”有什么问题。您正在编写服务器端代码,并且服务器拥有 URI 空间,因此根据请求 url 中的文本做出决策就是服务器的全部内容。
你可以使用类似的东西,

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

而不是搜索整个 uri 字符串,如果它能让你感觉不那么恶心的话!

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!

温折酒 2024-09-02 02:19:25

看起来像 该视频 即使在 WCF 数据服务中也能正常工作。您创建 ServiceAuthorizationManager 的自定义子类(请参阅 MSDN),覆盖 CheckAccessCore(),并在 web.config 中注册它。

我通过在请求的 HTTP 标头中传递密钥来使其工作。传递给 CheckAccessCoreOperationContext 并没有为您提供获取 HTTP 请求标头 的方法,但您可以通过 HttpContext.Current.Request 获取它们.标题。然后,您可以从该集合中获取正确的标头,并根据需要进行检查。

以下是 web.config 中必要的注册:

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

更新:关于能够从HttpContext.Current.Request.Headers获取标头,我错了;在 IIS 中运行时,HttpContext.Current 为 null(但有趣的是,在调试时不是)。相反,请按照此问题使用WebOperationContext.Current.IncomingRequest.Headers

更新2: HttpContext.Current 仅当您未在 ASP.NET 兼容模式下运行 WCF 时才为 null。您可以通过在 system.serviceModel 节点的应用程序级别将以下行添加到 web.config 来打开此功能:

<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>

如果您正在运行普通的 WCF 服务,还可以将其添加到服务的实现之上除了 ADO.NET 服务之外:

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]

然后您可以获得 HttpContext.Current.Request.Headers 以及 HttpRequest 类提供的所有其他内容。

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.

物价感观 2024-09-02 02:19:25

您可以检查请求类型并让 wsdl 调用在没有 api 密钥的情况下进行。

我不确定你的 api 目标是什么,但你可以使用客户端证书。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文