Origin
header, the server must respond using the Access-Control-Allow-Origin
header. Example of request / response pair from address foo.example
foo.example
on service bar.other/resources/public-data
bar.other/resources/public-data
:Request:
GET / resources / public-data / HTTP / 1.1
Host: bar.other
Origin:foo.example
[Other headers]
Answer:
HTTP / 1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Access-Control-Allow-Origin: *
Content-Type: application / xml
')
[XML Data]
Access-Control-Allow-Origin
- this header defines the resources from which requests may come. Can be used *
or a specific domain, for example foo.example
foo.example
. This header can be only one, and can contain only one value, i.e. domain list can not be set.Access-Control-Allow-Methods
- this header defines which methods can be used to communicate with the server. We confine ourselves to the following: POST,GET,OPTIONS
, but you can also use PUT
, and DELETE
, and others.Access-Control-Allow-Headers
— This header defines the list of available headers. For example, Content-Type
, which allows you to specify the type of application/json
response.Access-Control-Allow-Credentials
— This header determines whether the transfer of cookies and authorization is allowed. Possible values are true
and false
. Important: the data will be transmitted only if a specific domain is explicitly set up in the Access-Control-Allow-Origin
header, if you use *
, the header will be ignored and the data will not be transmitted.Access-Control-Allow-Headers
returns, or to the server, unless Access-Control-Allow-Credentials
and the correct Access-Control-Allow-Origin
. Before a POST
request to another domain, the browser will first make an OPTIONS
request ( preflight request ) for information on the allowed methods of working with the service. <system.webServer> <httpProtocol> <customHeaders> <add name="Access-Control-Allow-Origin" value="http://foo.example" /> <add name="Access-Control-Allow-Headers" value="Content-Type" /> <add name="Access-Control-Allow-Methods" value="POST, GET, OPTIONS" /> <add name="Access-Control-Allow-Credentials" value="true" /> </customHeaders> </httpProtocol> </system.webServer>
protected void Application_BeginRequest(object sender, EventArgs e) { var allowedOrigins = new [] { "http://foo.example", "http://bar.example" }; var request = HttpContext.Current.Request; var response = HttpContext.Current.Response; var origin = request.Headers["Origin"]; if (origin != null && allowedOrigins.Any(x => x == origin)) { response.AddHeader("Access-Control-Allow-Origin", origin); response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); response.AddHeader("Access-Control-Allow-Headers", "Content-Type, X-Requested-With"); response.AddHeader("Access-Control-Allow-Credentials", "true"); if (request.HttpMethod == "OPTIONS") { response.End(); } } }
[ServiceContract] public class MyService { [OperationContract] [WebInvoke(Method = "POST", ...)] public string DoStuff() { AddCorsHeaders(); return "<Data>"; } private void AddCorsHeaders() { var allowedOrigins = new [] { "http://foo.example", "http://bar.example" }; var request = WebOperationContext.Current.IncomingRequest; var response = WebOperationContext.Current.OutgoingResponse; var origin = request.Headers["Origin"]; if (origin != null && allowedOrigins.Any(x => x == origin)) { response.AddHeader("Access-Control-Allow-Origin", origin); response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); response.AddHeader("Access-Control-Allow-Headers", "Content-Type, X-Requested-With"); response.AddHeader("Access-Control-Allow-Credentials", "true"); if (request.HttpMethod == "OPTIONS") { response.End(); } } } }
AddCorsHeaders
call AddCorsHeaders
required in each service method. Plus - ease of use.EnableCorsBehavior
are created: using System; using System.ServiceModel.Channels; using System.ServiceModel.Configuration; using System.ServiceModel.Description; using System.ServiceModel.Dispatcher; namespace My.Web.Cors { public class EnableCorsBehavior : BehaviorExtensionElement, IEndpointBehavior { public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new EnableCorsMessageInspector()); } public void Validate(ServiceEndpoint endpoint) { } public override Type BehaviorType { get { return typeof(EnableCorsBehavior); } } protected override object CreateBehavior() { return new EnableCorsBehavior(); } } }
EnableCorsMessageInspector
: using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Dispatcher; namespace My.Web.Cors { public class EnableCorsMessageInspector : IDispatchMessageInspector { public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) { var allowedOrigins = new [] { "http://foo.example", "http://bar.example" }; var httpProp = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name]; if (httpProp != null) { string origin = httpProp.Headers["Origin"]; if (origin != null && allowedOrigins.Any(x => x == origin)) { return origin; } } return null; } public void BeforeSendReply(ref Message reply, object correlationState) { string origin = correlationState as string; if (origin != null) { HttpResponseMessageProperty httpProp = null; if (reply.Properties.ContainsKey(HttpResponseMessageProperty.Name)) { httpProp = (HttpResponseMessageProperty)reply.Properties[HttpResponseMessageProperty.Name]; } else { httpProp = new HttpResponseMessageProperty(); reply.Properties.Add(HttpResponseMessageProperty.Name, httpProp); } httpProp.Headers.Add("Access-Control-Allow-Origin", origin); httpProp.Headers.Add("Access-Control-Allow-Credentials", "true"); httpProp.Headers.Add("Access-Control-Request-Method", "POST,GET,OPTIONS"); httpProp.Headers.Add("Access-Control-Allow-Headers", "X-Requested-With,Content-Type"); } } } }
web.config
created by EnableCorsBehavior
: <system.serviceModel> ... <extensions> <behaviorExtensions> <add name="crossOriginResourceSharingBehavior" type="My.Web.Cors.EnableCorsBehavior, My.Web, Version=1.0.0.0, Culture=neutral" /> </behaviorExtensions> </extensions> ... </system.serviceModel>
EnableCorsBehavior
to the Behavior
configuration of our Endpoint
'a <system.serviceModel> <services> <service name="My.Web.Services.MyService"> <endpoint address="" behaviorConfiguration="My.Web.Services.MyService" binding="webHttpBinding" contract="My.Web.Services.MyService" /> </service> </services> ... <behaviors> ... <endpointBehaviors> ... <behavior name="My.Web.Services.MyService"> <webHttp/> <crossOriginResourceSharingBehavior /> <!-- --> </behavior> ... </endpointBehaviors> ... </behaviors> ... </system.serviceModel>
OPTIONS
method. In my case, I used the simplest option: the OPTIONS
request handler method is added to the service body. [OperationContract] [WebInvoke(Method = "OPTIONS", UriTemplate = "*")] public void GetOptions() { // EnableCorsMessageInspector }
GetOptions
method to the service body and a considerable amount of additional code. On the other hand, this approach allows almost completely separating the logic of the service and the logic of communication.withCredentials
flag is set to true
withCredentials
flag. I think that many people use jQuery to work with AJAX, so I’ll give an example for it: $.ajax({ type: 'POST', cache: false, dataType: 'json', xhrFields: { withCredentials: true }, contentType: 'application/json; charset=utf-8', url: options.serviceUrl + '/DoStuff' });
bar.other
bar.other
, we have the ability to return user data for an Ajax request from the site foo.example
foo.example
. In my case, this was used to enable the user to receive notifications and respond to events, being on one of the sites living within the same business project, but located on different domains and platforms. As mentioned above, the key points here are the header Access-Control-Allow-Credentials
and setting the flag for XmlHttpRequest
withCredentials=true
.Source: https://habr.com/ru/post/219895/
All Articles