.net CORS - 响应为401时丢失允许Origin标头 - 未经授权

时间:2014-06-20 14:39:06

标签: c# ajax cors

我正在尝试确定为什么/如何在响应为401-Unauthorized时丢失'Access-Control-Allow-Origin'标头。

我正在使用基于令牌的身份验证,其中令牌具有到期日期。当此令牌过期时,服务器将返回401未授权的,但在chrome(以及IE和FF)中,它永远不会看到Allow Origin标头和错误以及通常的CORS错误:XMLHttpRequest cannot load http://my.rest.service. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.

我不确定这些是否相关,因为auth逻辑工作正常,只是当响应为401时CORS会窒息。

C#CORS处理程序

namespace NViewREST.Handlers
{
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Threading;
    using System.Threading.Tasks;

    /// <summary>
    /// Handler for processing Cross Origin Resource Sharing (CORS) requests
    /// </summary>
    public class CorsHandler : DelegatingHandler
    {
        /// <summary>The origin.</summary>
        private const string Origin = "Origin";

        /// <summary>Header indicating we should treat this is CORS request.</summary>
        private const string EnableCors = "X-EnableCors";

        /// <summary>The access control request method.</summary>
        private const string AccessControlRequestMethod = "Access-Control-Request-Method";

        /// <summary>The access control request headers.</summary>
        private const string AccessControlRequestHeaders = "Access-Control-Request-Headers";

        /// <summary>The access control allow origin.</summary>
        private const string AccessControlAllowOrigin = "Access-Control-Allow-Origin";

        /// <summary>The access control allow methods.</summary>
        private const string AccessControlAllowMethods = "Access-Control-Allow-Methods";

        /// <summary>The access control allow headers.</summary>
        private const string AccessControlAllowHeaders = "Access-Control-Allow-Headers";

        /// <summary>
        /// send async request
        /// </summary>
        /// <param name="request">The request.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The <see cref="Task"/>.</returns>
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            // if it has our NFIB enable CORS header or has the access control request method header, we're assuming CORS request
            var isCorsRequest = request.Headers.Contains(AccessControlRequestMethod) || request.Headers.Contains(EnableCors);

            // preflight == OPTIONS request - usually only sent prior to CORS requests
            var isPreflightRequest = request.Method == HttpMethod.Options;

            // express exit if its a normal request
            if (!isCorsRequest)
            {
                return base.SendAsync(request, cancellationToken);
            }

            // actual CORS request - add appropriate header before executing as  normal
            if (!isPreflightRequest)
            {
                 return base.SendAsync(request, cancellationToken).ContinueWith(
                    t =>
                        {
                            var resp = t.Result;
                            resp.Headers.Add(AccessControlAllowOrigin, request.Headers.GetValues(Origin).First());
                            return resp;
                        },
                    cancellationToken);
            }

            // at this point its the preflight request - add headers to indicate allowed origins
            var response = new HttpResponseMessage(HttpStatusCode.OK);
            response.Headers.Add(AccessControlAllowOrigin, request.Headers.GetValues(Origin).First());

            // add header to indicate allowed methods
            var accessControlRequestMethod = request.Headers.GetValues(AccessControlRequestMethod).FirstOrDefault();
            if (accessControlRequestMethod != null)
            {
                response.Headers.Add(AccessControlAllowMethods, accessControlRequestMethod);
            }

            // add headers to indicate allowed headers
            var requestedHeaders = string.Join(", ", request.Headers.GetValues(AccessControlRequestHeaders));
            if (!string.IsNullOrEmpty(requestedHeaders))
            {
                response.Headers.Add(AccessControlAllowHeaders, requestedHeaders);
            }

            // send result of OPTIONS request
            var tcs = new TaskCompletionSource<HttpResponseMessage>();
            tcs.SetResult(response);
            return tcs.Task;
        }
    }
}

我可以单步执行添加标题的行,即使响应是401,所以我知道.net端正在添加它。

JavaScript Ajax调用

function executeAjax (method, url, data, token) {

    url = (url.indexOf('/') === 0) ? url : "/" + url;

    var options = {
        method: method,
        url: app.settings.apiUrlRoot + url,
        data: data
    };

    token = token || localStorage.getItem("sessionKey");

    options.headers = {
        "Accept": "application/json",

        //header for enabling CORS
        "X-EnableCors": 'true'
    }

    if (token !== undefined && token !== null)
    {
        options.headers["X-ADAuth"] = token,
    }

    return $.ajax(options);
};

此调用的结果是我之前引用的CORS错误。

我知道防火墙或中间件剥离这些问题没有问题,因为任何其他非401 ajax请求执行得很好。

为什么标题消失了?

1 个答案:

答案 0 :(得分:2)

我有完全相同的问题,并通过在返回之前将401 CORS标头添加到401响应来解决它。

var response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
response.Headers.WwwAuthenticate.Add(new AuthenticationHeaderValue("Bearer", "errorMessage"));
response.Headers.Add(AccessControlAllowOrigin, "*");
return response;