具有 CORS 和基本身份验证支持的 WCF 自托管数据服务
Posted
技术标签:
【中文标题】具有 CORS 和基本身份验证支持的 WCF 自托管数据服务【英文标题】:WCF Self-Hosted Data Services with CORS and Basic Auth support 【发布时间】:2013-05-26 05:43:10 【问题描述】:我正在构建一个 WCF 自托管数据服务(顺便说一下,OData),并且我正在使用基本身份验证来对用户进行身份验证。这并不难,我只需要一些配置步骤,构建一个 UserNamePasswordValidator 和一个 IAuthorizationPolicy - 完成。
现在我需要支持 CORS (Cross-Origin Resource Sharing)。我已经尝试了很多实现,一些有文档记录(例如,this),另一些是我自己制作的。
问题是,如果我启用基本身份验证,因为 CORS 预检请求 (OPTIONS) 没有“授权”标头,我无法操纵请求(当然,否则会破坏浏览器执行此操作的目的),我无法拦截/响应服务器上的请求。我什至无法检查它走了多远!我尝试实现许多行为、绑定、管理器等,但我无法捕获该请求,甚至在“DataService.OnStartProcessingRequest()”上也无法捕获。
如果我在服务器端禁用基本身份验证,我可以捕获 CORS 预检请求并最终响应它(使用 IDispatchMessageInspector 和 BehaviorExtensionElement),但我必须这样做我自己实现基本身份验证......该死。
请帮助我。 我如何实现两者?如何在 Basic Auth 简单地响应 401 Unauthorized 之前拦截 CORS 预检请求?
提前致谢。
【问题讨论】:
您好,您解决了吗?这个话题我也有问题 @acostela 你有解决方案吗,我也面临同样的问题。 【参考方案1】:首先,您可以处理所有“OPTIONS”请求以允许它们全部使用。 我使用以下技巧: 我的服务界面:
/// <summary>Handles ALL the http options requests.</summary>
[WebInvoke(Method = "OPTIONS", UriTemplate = "*")]
bool HandleHttpOptionsRequest();
实施:
/// <summary>Handles ALL the http options requests.</summary>
public bool HandleHttpOptionsRequest()
if (WebOperationContext.Current != null && WebOperationContext.Current.IncomingRequest.Method == "OPTIONS")
return true;
return false;
其次,需要在“CORS enabler”中添加Access-Control-Allow-Credentialsenable-cors
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
var requiredHeaders = new Dictionary<string, string>
"Access-Control-Allow-Credentials", "true" ,
"Access-Control-Allow-Origin", "*" ,
"Access-Control-Request-Method", "POST,GET,PUT,DELETE,OPTIONS" ,
"Access-Control-Allow-Headers", "X-Requested-With,Content-Type,Safe-Repository-Path,Safe-Repository-Token"
;
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new CustomHeaderMessageInspector(requiredHeaders));
【讨论】:
【参考方案2】:在下面提到的情况下,我是如何解决这个问题的:
/// <summary>
/// Class written to check for whether the REST calls is authorised.
/// </summary>
public class RestServiceAuthorizationManger : ServiceAuthorizationManager
/// <summary>
/// Method to check for basic authorization in rest service calls.
/// </summary>
protected override bool CheckAccessCore(OperationContext operationContext)
try
bool Verified = false;
if (WebOperationContext.Current != null &&
WebOperationContext.Current.IncomingRequest.Method == "OPTIONS")
WebOperationContext.Current.OutgoingResponse.StatusCode =
HttpStatusCode.OK;
return true;
else
//Extract the Authorization header, and parse out the credentials converting the Base64 string:
var authHeader = WebOperationContext.Current.IncomingRequest.Headers["Authorization"];
if ((authHeader != null) && (authHeader != string.Empty))
//You code to check for authorization credentials from incoming authorization headers.
else
//Throw an exception with the associated HTTP status code equivalent to HTTP status 401
//No authorization header was provided, so challenge the client to provide before proceeding:
//WebOperationContext.Current.OutgoingResponse.Headers.Add("WWW-Authenticate: Basic realm=\"RestServiceAuthorizationManger\"");
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Unauthorized;
WebOperationContext.Current.OutgoingResponse.StatusDescription = "Unauthorized";
return false;
catch(Exception ex)
//Throw an exception with the associated HTTP status code equivalent to HTTP status 401
//No authorization header was provided, so challenge the client to provide before proceeding:
//WebOperationContext.Current.OutgoingResponse.Headers.Add("WWW-Authenticate: Basic realm=\"RestServiceAuthorizationManger\"");
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Unauthorized;
WebOperationContext.Current.OutgoingResponse.StatusDescription = "Unauthorized";
return false;
public class EnableCorsSupportBehavior : IEndpointBehavior
public void Validate(ServiceEndpoint endpoint)
public void AddBindingParameters(ServiceEndpoint endpoint,
BindingParameterCollection bindingParameters)
public void ApplyDispatchBehavior(ServiceEndpoint endpoint,
EndpointDispatcher endpointDispatcher)
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(
new CorsEnablingMessageInspector());
public void ApplyClientBehavior(ServiceEndpoint endpoint,
ClientRuntime clientRuntime)
public class CorsEnablingMessageInspector : IDispatchMessageInspector
public object AfterReceiveRequest(ref Message request,
IClientChannel channel, InstanceContext instanceContext)
var httpRequest = (HttpRequestMessageProperty)request
.Properties[HttpRequestMessageProperty.Name];
return new
origin = httpRequest.Headers["Origin"],
handlePreflight = httpRequest.Method.Equals("OPTIONS",
StringComparison.InvariantCultureIgnoreCase)
;
public void BeforeSendReply(ref Message reply, object correlationState)
var state = (dynamic)correlationState;
// handle request preflight
if (state != null && state.handlePreflight)
reply = Message.CreateMessage(MessageVersion.None, "PreflightReturn");
var httpResponse = new HttpResponseMessageProperty();
reply.Properties.Add(HttpResponseMessageProperty.Name, httpResponse);
httpResponse.SuppressEntityBody = true;
httpResponse.StatusCode = HttpStatusCode.OK;
// add allowed origin info
var response = (HttpResponseMessageProperty)reply.Properties[HttpResponseMessageProperty.Name];
response.Headers.Add("Access-Control-Allow-Origin", "*");
response.Headers.Add("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE,PATCH, OPTIONS");
response.Headers.Add("Access-Control-Allow-Headers", "Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers, Authorization");
response.Headers.Add("Access-Control-Allow-Credentials", "true");
希望这可以帮助某人。谢谢!
【讨论】:
以上是关于具有 CORS 和基本身份验证支持的 WCF 自托管数据服务的主要内容,如果未能解决你的问题,请参考以下文章