如何在 WCF 数据服务中实现 API 密钥?
题
有没有办法要求 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。有没有更好的办法?
解决方案
我建议使用授权报头传递apiKey而不是传递它在查询串中的。这就是它是有它帮助的保持API密钥了日志文件。
我不觉得有什么真的错了与检查“$元数据”的在URL中存在。你正在写的服务器端代码和服务器拥有的URI空间,所以使得基于请求URL文本决定是服务器的全部。 你可以使用像,
if (requestUrl.Segments.Last().Replace('/','') != '$metadata')
而不是搜索整个URI字符串,如果这能让它感觉不到恶心!
其他提示
看起来像中介绍的技术 这个视频 即使在 WCF 数据服务中也能正常工作。您创建一个自定义子类 ServiceAuthorizationManager
(看 微软软件定义网络), 覆盖 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 中运行时为 null(但有趣的是在调试时不是)。相反,使用 WebOperationContext.Current.IncomingRequest.Headers
按照 这个问题.
更新2: HttpContext.Current
仅当您未在 ASP.NET 兼容模式下运行 WCF 时,才为 null。您可以通过将以下行添加到应用程序级别的 web.config 中来打开此功能 system.serviceModel
节点:
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
如果除了 ADO.NET 服务之外还运行着普通的 WCF 服务,还要在服务的实现上方添加此内容:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
然后你可以得到 HttpContext.Current.Request.Headers
以及由 HttpRequest
班级。
您可以检查请求的类型和让WSDL与呼叫出来的API密钥去。
我不知道您的API的目标是什么,但你可以使用客户端证书。