【问题标题】:Handling CORS Preflight in Asp.net Web API在 Asp.net Web API 中处理 CORS 预检
【发布时间】:2015-09-26 05:23:45
【问题描述】:

我的架构中有三个应用程序。
它们在同一台服务器上,但具有不同的端口号。

A - Token Application (port 4444) - Asp.net WebApi
B - API Application   (port 3333) - Asp.net WebApi
C - UI Application    (port 2222) - AngularJS App.

申请流程如下

1- UI 项目从令牌应用程序获取令牌(它需要 Windows 身份验证。) 例如:awxrsdsaWeffs12da

2- UI 应用程序将此令牌放入名为“accessToken”的自定义标头中

例如:accessToken:awxrsdsaWeffs12da

3- UI 应用程序向 API 应用程序发送请求 例如:http:myaddress:3333/api/TheRestServiceHere

UI 应用程序出现 401 错误。 它发送 OPTIONS 方法。 (我猜是预检问题)

在我的 web api 项目中,我启用了如下所示的 Cors。

public static void Register(HttpConfiguration config)
{
            ....

            //CORS
            var cors = new EnableCorsAttribute("*", "*", "*");
            config.EnableCors(cors);

            ....
}

配置

   public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {

            //CORS
            var cors = new EnableCorsAttribute("*", "*", "*");
            config.EnableCors();


            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );


            var json = config.Formatters.JsonFormatter;
            json.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.None;
            json.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
            json.SerializerSettings.Formatting = Formatting.None;
            json.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();

            config.Formatters.Remove(config.Formatters.XmlFormatter);
        }
    }

所以我正在寻找调用 API 应用程序 (B) 控制器的解决方案 并获得 200 :)

问候

【问题讨论】:

  • 你能用你的 web api“路由配置”更新你的问题吗?
  • 从浏览器调用WebAPI时能找到JSON结果吗?
  • 是的,我可以通过邮递员和浏览器拨打电话。

标签: c# angularjs asp.net-web-api http-headers cors


【解决方案1】:

我的一个朋友使用 OPTIONSVerbHandler 解决了这个问题。

当 UI 应用想要使用 GET 方法时,浏览器发送 OPTION 方法首先发送到服务器(预检)。然后,如果 Preflight 请求正常,它会发送 GET 请求。

出于 CORS 测试目的,我们使用以下代码发送 GET 方法。

<html>
<head>
    <script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
    <script>
    $( document ).ready(function() {
        var adress = "http://10.10.27.36:3434/backend/api/role";

        $.ajaxSetup({
            headers: { 
            'Content-Type': 'application/json',
            'accessToken': 'some value',
            'Origin' : ''
            }
        });

        $.ajax({
        type: "GET",
        url: adress,
        dataType: "json"
        });

    });

    </script></head><body></body></html>

要在 GET 之前处理浏览器发送的 OPTION 方法,您应该具有以下设置。

1- 网络配置

<system.webServer>
    <handlers>
        <add name="OPTIONSVerbHandler" path="*" verb="OPTIONS" modules="ProtocolSupportModule" resourceType="Unspecified" requireAccess="None" />
    </handlers>
</system.webServer> 

2- 使用以下设置添加 OPTIONSVerbHandler

点击请求限制

3- 我们的标头设置我们有 accessToken,如您所见,这是自定义的

【讨论】:

  • 我在遵循此解决方案时遇到了问题,因为没有提示如何访问这些屏幕截图中显示的表单。
  • 嗨,前两个来自 chrome,其余来自 iis > 处理程序映射
【解决方案2】:

我通过创建一个响应使用 OPTIONS 动词的请求的模块,在我正在处理的应用程序中解决了这个问题。您可能应该稍微修改一下以包含应用程序请求的动词和内容类型。就我而言,我决定将所有内容都发布为 JSON(这需要飞行前检查)。模块如下:

public class OptionsModule : IHttpModule
{
    public void Init(HttpApplication context)
    {
        context.BeginRequest += (sender, args) =>
        {
            var app = (HttpApplication) sender;

            if (app.Request.HttpMethod == "OPTIONS")
            {
                app.Response.StatusCode = 200;
                app.Response.AddHeader("Access-Control-Allow-Headers", "content-type");
                app.Response.AddHeader("Access-Control-Allow-Origin", APISettings.ApplicationOrigin);
                app.Response.AddHeader("Access-Control-Allow-Credentials", "true");
                app.Response.AddHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS");
                app.Response.AddHeader("Content-Type", "application/json");
                app.Response.End();
            }
        };
    }

    public void Dispose()
    {
    }
}

然后你需要在你的 web.config 中注册它:

<system.webServer>
    <modules>
      <add name="HandleOptions" type="namespace.OptionsModule" />
    </modules>
</system.webServer>

您可能想要做的另一件事是明确指定允许的来源。 Chrome 不喜欢在那里使用通配符。

【讨论】:

  • 嗨 Jereme,关于“APISettings.ApplicationOrigin”的问题来自哪里?
  • 它来自 Web.config。当我部署到不同的环境时,那里的值会发生变化,因此可以轻松地在环境级别发布和锁定访问。
  • 这个答案值得更多的赞成票。我花了几天时间试图弄清楚这个问题。这是唯一对我有用的东西。
  • 您好 Jereme,我看到您的回答更方便。我标记为答案。
  • 这太棒了!我所做的一项更改是让该模块仅响应带有 Access-Control-Request-* 标头的请求,这样非预检 OPTIONS 请求就不会被拦截。
【解决方案3】:

适用于 Azure 环境

您需要允许来自门户的来源。

【讨论】:

  • CORS 设置为允许所有在 startup.cs,我认为这不会导致不同的结果。无论如何,这是 Azure 特有的。
猜你喜欢
  • 2021-06-25
  • 1970-01-01
  • 2014-10-31
  • 2017-10-16
  • 2012-11-17
  • 2015-02-04
  • 2015-01-06
  • 2016-10-07
  • 2012-07-26
相关资源
最近更新 更多