我有一个 WebAPI 控制器,该类具有自定义 CORS 策略提供程序属性。 在定义属性时,我有以下构造函数。
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)]
public class ConfiguredCORSPolicyProviderAttribute : ActionFilterAttribute, ICorsPolicyProvider
{
private CorsPolicy _policy;
public ConfiguredCORSPolicyProviderAttribute()
{
_policy = new CorsPolicy
{
AllowAnyMethod = true,
AllowAnyHeader = true
};
// If there are no domains in the 'CORSDomainSection' section in Web.config, all origins will be allowed by default.
var domains = (CORSDomainSection)ConfigurationManager.GetSection("CORSDomainSection");
if (domains != null)
{
foreach (DomainConfigElement domain in domains.Domains)
{
_policy.Origins.Add(domain.Domain);
}
}
else
{
_policy.AllowAnyOrigin = true;
}
}
public Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request)
{
return Task.FromResult(_policy);
}
public Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request, CancellationToken token)
{
return GetCorsPolicyAsync(request);
}
}
配置管理器获取一个列表(来自 Web.config(,其中包含我希望允许发出请求的可接受源/域。
此代码适当地处理"访问控制-允许源"标头,当请求源在列表中时添加它,当不在列表中时保留它。 但是,无论如何,控制器中的代码仍然会被调用。
为什么,如果不允许请求的来源,如何适当地阻止控制器执行?
更新 || [四月 12, 2016 @ 12:30p]
我能够使用OnActionExecuted
和OnActionExecuting
方法覆盖的组合来解决问题,代码如下。
/// <summary>
/// Executed after the action method is invoked.
/// </summary>
/// <param name="context">The context of the HTTP request.</param>
public override void OnActionExecuted(HttpActionExecutedContext context)
{
string requestOrigin;
try
{
requestOrigin = context.Request.Headers.GetValues("Origin").FirstOrDefault();
}
catch
{
requestOrigin = string.Empty;
}
if (IsAllowedOrigin(requestOrigin))
{
context.Response.Headers.Add("Access-Control-Allow-Origin", requestOrigin);
if (IsPreflight(context))
{
string allowedMethods = string.Empty;
string allowedHeaders = string.Empty;
if (Policy.AllowAnyMethod)
{
allowedMethods = context.Request.Headers.GetValues("Access-Control-Request-Method").FirstOrDefault();
}
else
{
foreach (var method in Policy.Methods)
{
if (Policy.Methods.IndexOf(method) == 0)
{
allowedMethods = method;
}
else
{
allowedMethods += string.Format(", {0}", method);
}
}
}
try
{
if (Policy.AllowAnyHeader)
{
allowedHeaders = context.Request.Headers.GetValues("Access-Control-Request-Headers").FirstOrDefault();
}
else
{
foreach (var header in Policy.Headers)
{
if (Policy.Headers.IndexOf(header) == 0)
{
allowedHeaders = header;
}
else
{
allowedHeaders += string.Format(", {0}", header);
}
}
}
context.Response.Headers.Add("Access-Control-Allow-Headers", allowedHeaders);
}
catch
{
// Do nothing.
}
context.Response.Headers.Add("Access-Control-Allow-Methods", allowedMethods);
}
}
base.OnActionExecuted(context);
}
/// <summary>
/// Executed before the action method is invoked.
/// </summary>
/// <param name="context">The context of the HTTP request.</param>
public override void OnActionExecuting(HttpActionContext context)
{
string requestOrigin;
try
{
requestOrigin = context.Request.Headers.GetValues("Origin").FirstOrDefault();
}
catch
{
requestOrigin = string.Empty;
}
if (IsAllowedOrigin(requestOrigin))
{
base.OnActionExecuting(context);
}
else
{
context.ModelState.AddModelError("State", "The origin of the request is forbidden from making requests.");
context.Response = context.Request.CreateErrorResponse(HttpStatusCode.Forbidden, context.ModelState);
}
}
private bool IsAllowedOrigin(string requestOrigin)
{
requestOrigin = requestOrigin.Replace("https://", "").Replace("http://", "");
if (System.Diagnostics.Debugger.IsAttached || PolicyContains(requestOrigin))
{
return true;
}
else
{
return false;
}
}
private bool PolicyContains(string requestOrigin)
{
foreach (var domain in _policy.Origins)
{
if (domain.Replace("https://", "").Replace("http://", "") == requestOrigin)
{
return true;
}
}
return false;
}
private bool IsPreflight(HttpActionExecutedContext context)
{
string header = string.Empty;
try
{
header = context.Request.Headers.GetValues("Access-Control-Request-Method").FirstOrDefault();
}
catch
{
return false;
}
if (header != null && context.Request.Method == HttpMethod.Options)
{
return true;
}
else
{
return false;
}
}
CORS 标头预计不会阻止对控制器的调用 - 即,如果本机客户端(几乎任何不是浏览器的东西(调用该方法,则应默认处理该方法。
如果您确实需要阻止此类调用 - 在控制器被调用之前执行类似的检查 OnActionExecutingAsync
.