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

Posted

技术标签:

【中文标题】.net CORS - 响应为 401 时丢失 Allow Origin 标头 - 未授权【英文标题】:.net CORS - Losing Allow Origin header when the response is 401 - not authorized 【发布时间】:2014-08-11 08:43:17 【问题描述】:

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

我正在使用基于令牌的身份验证,其中令牌具有到期日期。当这个令牌过期时,服务器会返回一个 401-unauthorized,因为它应该,但在 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.

我不确定这些是否相关,因为身份验证逻辑工作正常,只是当响应为 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】:

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

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

【讨论】:

AccessControlAllowOrigin 在哪个命名空间?

以上是关于.net CORS - 响应为 401 时丢失 Allow Origin 标头 - 未授权的主要内容,如果未能解决你的问题,请参考以下文章

401 未经授权响应 CORS 预检选项请求

.net 核心允许在使用 CORS 时发回错误 401(而不是零)

401 响应 CORS preflight OPTIONS 请求到 Spring Boot 服务器

ASP.NET Core 5 JWT 身份验证失败,响应代码为 401

Yii2 和 reactjs CORS 过滤器给出错误:预检响应具有无效的 HTTP 状态代码 401

删除和选项请求获得 401 未授权响应