Come si è visto ...
CORS intestazioni non sono attesi PREVENIRE le chiamate a un controller: MVC o Web API. Si limita a impedire che i RISULTATI vengano restituiti al browser. Il metodo verrà eseguito indipendentemente da cosa ... quindi devi impedire l'esecuzione con altri mezzi.
QUALI ALTRI MEZZI?
Probabilmente è possibile farlo utilizzando uno AuthorizeAttribute
. Ma volevo farlo al livello di azione, così ho scelto un ActionFilterAttribute
- ed eseguito controlli in in OnActionExecuting
Note sull'utilizzo: L'ActionFilterAttribute
Ciò significa cose come SQL CLR
chiamate da un database (che è quello che sto facendo) non funzionerà perché la REFERRER
è nullo (a causa di questo, io sarò il distacco di una soluzione di meglio in seguito).
- Il
ICorsPolicyProvider
è inutile - sono rimuoverlo (ma incluso qui)
Tutti gli esempi che ho visto la incluse, ma devo ancora trovare uno scenario in cui esso viene chiamato. Il mio costruttore crea già il CorsPolicy
& la politica è disponibile per tutta la durata delle chiamate ... quindi il metodo ICorsPolicyProvider
sembra abbastanza inutile (al momento).
Il TraceHandler
implementazione è la mia - andare avanti & utilizzare il proprio posto
L'intestazione Access-Control-Allow-Origin
doveva essere aggiunto per garantire un comportamento di ritorno messaggio previsto per alcuni clienti
QUI È IL CODICE: The ActionFilterAttribute
namespace My.Application.Security
{
using My.Application.Diagnostics;
using System;
using System.Configuration;
using System.Diagnostics;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Cors;
using System.Web.Http.Controllers;
using System.Web.Http.Cors;
using System.Web.Http.Filters;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class EnableWebApiCorsFromAppSettingsAttribute : ActionFilterAttribute, ICorsPolicyProvider
{
#region <Fields & Constants>
private const string EXCEPTION_CONTEXT_NULL = "Access Denied: HttpActionContext cannot be null.";
private const string EXCEPTION_REFERRER_NULL = "Access Denied: Referrer cannot be null.";
private const string FORMAT_INVALID_REFERRER = "Access Denied: '{0}' is not a valid referrer.";
private const string FORMAT_REFERRER = "Referrer: '{0}' was processed for this request.";
private const string FORMAT_REFERRER_FOUND = "Referrer IsFound: {0}.";
private readonly CorsPolicy policy;
#endregion
#region <Constructors>
public EnableWebApiCorsFromAppSettingsAttribute(string appSettingKey, bool allowAnyHeader = true, bool allowAnyMethod = true, bool supportsCredentials = true)
{
policy = new CorsPolicy();
policy.AllowAnyOrigin = false;
policy.AllowAnyHeader = allowAnyHeader;
policy.AllowAnyMethod = allowAnyMethod;
policy.SupportsCredentials = supportsCredentials;
SetValidOrigins(appSettingKey);
if (policy.Origins.Count == 0)
policy.AllowAnyOrigin = true;
}
#endregion
#region <Methods>
#region public
public override void OnActionExecuting(HttpActionContext actionContext)
{
TraceHandler.TraceIn(TraceLevel.Info);
if (actionContext == null)
throw new ArgumentNullException("HttpActionContext");
if (actionContext.Request.Headers.Referrer == null)
actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.Forbidden, EXCEPTION_REFERRER_NULL);
var referrer = actionContext.Request.Headers.Referrer.ToString();
TraceHandler.TraceAppend(string.Format(FORMAT_REFERRER, referrer));
// If no Origins Are Set - Do Nothing
if (policy.Origins.Count > 0)
{
var isFound = policy.Origins.Contains(referrer);
TraceHandler.TraceAppend(string.Format(FORMAT_REFERRER_FOUND, isFound));
if (!isFound)
{
TraceHandler.TraceAppend("IsFound was FALSE");
actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.Forbidden, string.Format(FORMAT_INVALID_REFERRER, referrer));
}
}
TraceHandler.TraceOut();
base.OnActionExecuting(actionContext);
}
public Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (cancellationToken.CanBeCanceled && cancellationToken.IsCancellationRequested)
return Task.FromResult<CorsPolicy>(null);
return Task.FromResult(policy);
}
#endregion
#region private
private void SetValidOrigins(string appSettingKey)
{
// APP SETTING KEY: <add key="EnableCors.Origins" value="http://www.zippitydoodah.com" />
var origins = string.Empty;
if (!string.IsNullOrEmpty(appSettingKey))
{
origins = ConfigurationManager.AppSettings[appSettingKey];
if (!string.IsNullOrEmpty(origins))
{
foreach (string origin in origins.Split(",;|".ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
policy.Origins.Add(origin);
}
}
}
#endregion
#endregion
}
}
ECCO UTILIZZO DEL CODICE: L'ActionFilterAttribute
namespace My.Application.Web.Controllers
{
using Security;
using My.Application.Diagnostics;
using My.Application.Framework.Configuration;
using My.Application.Models;
using My.Application.Process;
using System;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Messaging;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Cors;
using System.Xml.Linq;
using System.Xml.Serialization;
[EnableCors(origins: "*", headers: "*", methods: "*")]
public class OutboundEventController : ApiControllerBase
{
#region <Actions>
[HttpGet]
public HttpResponseMessage Ping()
{
TraceHandler.TraceIn(TraceLevel.Info);
if (Request.Headers.Referrer == null)
TraceHandler.TraceAppend(MESSAGE_REFERRER_NULL);
if (Request.Headers.Referrer != null)
TraceHandler.TraceAppend(string.Format(FORMAT_REFERRER, Request.Headers.Referrer));
TraceHandler.TraceOut();
return Request.CreateResponse(HttpStatusCode.OK, "Ping back at cha...");
}
[HttpPost]
[EnableWebApiCorsFromAppSettings("EnableCors.Origins")]
public HttpResponseMessage Enqueue(HttpRequestMessage request)
{
TraceHandler.TraceIn(TraceLevel.Info);
if (Request.Headers.Referrer == null)
TraceHandler.TraceAppend(MESSAGE_REFERRER_NULL);
if (Request.Headers.Referrer != null)
TraceHandler.TraceAppend(string.Format(FORMAT_REFERRER, Request.Headers.Referrer));
try
{
// Do Amazing Stuff Here...
TraceHandler.TraceAppend(FORMAT_ENQUEUED_SUCCESS, claimId);
}
catch (Exception ex)
{
TraceHandler.TraceError(ex);
TraceHandler.TraceOut();
EnqueueToPoison(ex, claimMessage);
return Request.CreateResponse(HttpStatusCode.InternalServerError, GetHttpError());
}
TraceHandler.TraceOut();
// FORCE: Correct Header
var response = Request.CreateResponse(HttpStatusCode.OK, string.Format(FORMAT_ENQUEUED_SUCCESS, claimId));
response.Headers.Add("Access-Control-Allow-Origin", "*");
return response;
}
#endregion
private string GetClaimId(HttpRequestMessage request)
{
var stream = request.Content.ReadAsStreamAsync().Result;
var xdoc = XDocument.Load(stream);
var result = GetElementValue(xdoc, "ClaimId");
return result;
}
private ClaimMessage CreateClaimMessage(string claimId, string process)
{
ClaimMessage message = new ClaimMessage();
message.ClaimID = claimId;
message.Process = process;
return message;
}
private void Enqueue(ClaimMessage claimMessage)
{
var queueName = ConfigurationManager.AppSettings[Settings.Messaging.Queue.Name].ToString();
var queue = new MessageQueue(queueName);
queue.DefaultPropertiesToSend.Recoverable = true;
TraceHandler.TraceAppend(FORMAT_QUEUE_NAME, queueName);
MessageQueueTransaction transaction;
transaction = new MessageQueueTransaction();
transaction.Begin();
var message = new System.Messaging.Message();
message.Formatter = new XmlMessageFormatter(new Type[] { typeof(ClaimMessage) });
message.Label = "ClaimID " + claimMessage.ClaimID;
message.Body = claimMessage;
queue.Send(message, transaction);
transaction.Commit();
queue.Close();
}
private void EnqueueToPoison(Exception exception, ClaimMessage claimdata)
{
TraceHandler.TraceIn(TraceLevel.Info);
var poison = ToPoisonMessage(exception, claimdata);
var message = new System.Messaging.Message();
try
{
var poisonQueueName = ConfigurationManager.AppSettings[Settings.Messaging.PoisonQueue.Name].ToString();
TraceHandler.TraceAppend(FORMAT_QUEUE_NAME, poisonQueueName);
if (MessageQueue.Exists(poisonQueueName))
{
var queue = new MessageQueue(poisonQueueName);
queue.DefaultPropertiesToSend.Recoverable = true;
var transaction = new MessageQueueTransaction();
transaction.Begin();
message.Formatter = new XmlMessageFormatter(new Type[] { typeof(PoisonClaimMessage) });
message.Label = "Poison ClaimID " + poison.ClaimID;
var xmlSerializer = new XmlSerializer(poison.GetType());
xmlSerializer.Serialize(message.BodyStream, poison);
queue.Send(message, transaction);
TraceHandler.TraceAppend(FORMAT_ENQUEUED_POISON_SUCCESS, poison.ClaimID);
transaction.Commit();
queue.Close();
}
}
catch(Exception ex)
{
// An error occurred while enqueuing to POISON
var poisonXml = ToString(poison);
TraceHandler.TraceError(ex);
TraceHandler.TraceAppend(poisonXml);
}
finally
{
TraceHandler.TraceOut();
}
}
#endregion
}
}
IMPOSTAZIONI DI APPLICAZIONE: La ActionFilterAttribute
<appSettings>
<add key="EnableCors.Origins" value="" />
</appSettings>
fa [questo] (http: //www.britishdeveloper .co.uk/2015/12/stop-processing-options-requests-for.html) aiuto? – cableload
+1 Finora, gestisco "tutto" (comprese le richieste senza browser, perché avvengono) tramite token (ovvero "intestazione di autenticazione"). – EdSF
@ EDSF Aiutami a capire cosa significa? –