Angularjs CORS飞行前请求响应Azure托管Web API中的302重定向

Angularjs CORS飞行前请求响应Azure托管Web API中的302重定向,angularjs,azure,asp.net-web-api,cors,adal,Angularjs,Azure,Asp.net Web Api,Cors,Adal,场景: Request OPTIONS /api/items HTTP/1.1 Host: webapi.azurewebsites.net Connection: keep-alive Access-Control-Request-Method: GET Access-Control-Request-Headers: accept, authorization Origin: https://mvcapp.azurewebsites.net User-Agent: Mozilla/5.0 (W

场景:

Request OPTIONS /api/items HTTP/1.1 Host: webapi.azurewebsites.net Connection: keep-alive Access-Control-Request-Method: GET Access-Control-Request-Headers: accept, authorization Origin: https://mvcapp.azurewebsites.net User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36 Accept: */* Referer: https://mvcapp.azurewebsites.net/ Response HTTP/1.1 302 Found Content-Length: 504 Location: https://login.windows.net/{authority-guid}/oauth2/authorize?response_type=id_token&redirect_uri=https%3A%2F%2F....etc..etc.%2F&client_id={api-guid}&scope=openid+profile+email&response_mode=form_post&state=...etc... Server: Microsoft-IIS/8.0 X-Powered-By: ASP.NET Set-Cookie: ARRAffinity=4f51...snip....redact....db6d;Path=/;Domain=webapi.azurewebsites.net 我有两个ASP.NET web应用程序分别托管在Windows Azure上,并且都与同一Azure Active Directory租户关联:

  • 具有AngularJS SPA前端和库的MVC应用程序,用于在客户端上处理Azure广告验证

  • 带有Microsoft OWIN中间件的Web API,用于在服务器上处理Azure AD身份验证

  • 问题:

    Request OPTIONS /api/items HTTP/1.1 Host: webapi.azurewebsites.net Connection: keep-alive Access-Control-Request-Method: GET Access-Control-Request-Headers: accept, authorization Origin: https://mvcapp.azurewebsites.net User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36 Accept: */* Referer: https://mvcapp.azurewebsites.net/ Response HTTP/1.1 302 Found Content-Length: 504 Location: https://login.windows.net/{authority-guid}/oauth2/authorize?response_type=id_token&redirect_uri=https%3A%2F%2F....etc..etc.%2F&client_id={api-guid}&scope=openid+profile+email&response_mode=form_post&state=...etc... Server: Microsoft-IIS/8.0 X-Powered-By: ASP.NET Set-Cookie: ARRAffinity=4f51...snip....redact....db6d;Path=/;Domain=webapi.azurewebsites.net 当angular引导客户端应用程序时,页面在通过oauth重定向到正确的身份验证机构后正确加载,adal.js库为每个应用程序正确检索和存储不同的令牌(通过检查Chrome dev tools中的Resources/Session Storage选项卡进行验证)。但是,当客户端应用程序尝试访问或更新API中的任何数据时,CORS飞行前请求将响应302个指向身份验证机构的重定向,这将导致控制台中出现以下错误:

    无法加载XMLHttpRequest。 请求已重定向到 “{authority guid}/oauth2/authority?响应\u type=id\u令牌和重定向\u uri=…..等…”, 这是不允许的跨来源请求,需要飞行前

    示例标题(匿名):

    Request OPTIONS /api/items HTTP/1.1 Host: webapi.azurewebsites.net Connection: keep-alive Access-Control-Request-Method: GET Access-Control-Request-Headers: accept, authorization Origin: https://mvcapp.azurewebsites.net User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36 Accept: */* Referer: https://mvcapp.azurewebsites.net/ Response HTTP/1.1 302 Found Content-Length: 504 Location: https://login.windows.net/{authority-guid}/oauth2/authorize?response_type=id_token&redirect_uri=https%3A%2F%2F....etc..etc.%2F&client_id={api-guid}&scope=openid+profile+email&response_mode=form_post&state=...etc... Server: Microsoft-IIS/8.0 X-Powered-By: ASP.NET Set-Cookie: ARRAffinity=4f51...snip....redact....db6d;Path=/;Domain=webapi.azurewebsites.net OWIN中间件初始化

    angular.module("myApp", ["ngRoute", "AdalAngular"])
    
    .config(["$routeProvider", "$locationProvider", "$httpProvider", "adalAuthenticationServiceProvider",
        function ($routeProvider, $locationProvider, $httpProvider, adalProvider) {
    
            $routeProvider.when("/", { // other routes omitted for brevity
                templateUrl: "/content/views/home.html",
                requireADLogin: true // restrict to validated users in the Azure AD tenant
            });
    
            // CORS support (I've tried with and without this line)
            $httpProvider.defaults.withCredentials = true;
    
            adalProvider.init({
                tenant: "contoso.onmicrosoft.com",
                clientId: "11111111-aaaa-2222-bbbb-3333cccc4444", // Azure id of the web app
                endpoints: {
                    // URL and Azure id of the web api
                    "https://webapi.azurewebsites.net/": "99999999-zzzz-8888-yyyy-7777xxxx6666"
                }
            }, $httpProvider);
        }
    ]);
    
    public void ConfigureAuth(IAppBuilder app)
    {
        // I've tried with and without the below line and also by passing
        // in a more restrictive and explicit custom CorsOptions object
        app.UseCors(CorsOptions.AllowAll);
    
        app.UseWindowsAzureActiveDirectoryBearerAuthentication(
            new WindowsAzureActiveDirectoryBearerAuthenticationOptions
            {
                TokenValidationParameters = new TokenValidationParameters
                {
                    // Azure id of the Web API, also tried the client app id
                    ValidAudience = "99999999-zzzz-8888-yyyy-7777xxxx6666"
                },
                Tenant = "contoso.onmicrosoft.com"
            }
        );
    
        // I've tried with and without this
        app.UseWebApi(GlobalConfiguration.Configuration);
    }
    
    public static void Register(HttpConfiguration config)
    {
        // I've tried with and without this and also using both this
        // and the OWIN CORS setup above. Decorating the ApiControllers
        // or specific Action methods with a similar EnableCors attribute
        // also doesn't work.
        var cors = new EnableCorsAttribute("https://mvcapp.azurewebsites.net", "*", "*")
        {
            cors.SupportsCredentials = true // tried with and without
        };
        config.EnableCors(cors);
    
        // Route registration and other initialization code removed
    }
    
    WebApiConfig初始化

    angular.module("myApp", ["ngRoute", "AdalAngular"])
    
    .config(["$routeProvider", "$locationProvider", "$httpProvider", "adalAuthenticationServiceProvider",
        function ($routeProvider, $locationProvider, $httpProvider, adalProvider) {
    
            $routeProvider.when("/", { // other routes omitted for brevity
                templateUrl: "/content/views/home.html",
                requireADLogin: true // restrict to validated users in the Azure AD tenant
            });
    
            // CORS support (I've tried with and without this line)
            $httpProvider.defaults.withCredentials = true;
    
            adalProvider.init({
                tenant: "contoso.onmicrosoft.com",
                clientId: "11111111-aaaa-2222-bbbb-3333cccc4444", // Azure id of the web app
                endpoints: {
                    // URL and Azure id of the web api
                    "https://webapi.azurewebsites.net/": "99999999-zzzz-8888-yyyy-7777xxxx6666"
                }
            }, $httpProvider);
        }
    ]);
    
    public void ConfigureAuth(IAppBuilder app)
    {
        // I've tried with and without the below line and also by passing
        // in a more restrictive and explicit custom CorsOptions object
        app.UseCors(CorsOptions.AllowAll);
    
        app.UseWindowsAzureActiveDirectoryBearerAuthentication(
            new WindowsAzureActiveDirectoryBearerAuthenticationOptions
            {
                TokenValidationParameters = new TokenValidationParameters
                {
                    // Azure id of the Web API, also tried the client app id
                    ValidAudience = "99999999-zzzz-8888-yyyy-7777xxxx6666"
                },
                Tenant = "contoso.onmicrosoft.com"
            }
        );
    
        // I've tried with and without this
        app.UseWebApi(GlobalConfiguration.Configuration);
    }
    
    public static void Register(HttpConfiguration config)
    {
        // I've tried with and without this and also using both this
        // and the OWIN CORS setup above. Decorating the ApiControllers
        // or specific Action methods with a similar EnableCors attribute
        // also doesn't work.
        var cors = new EnableCorsAttribute("https://mvcapp.azurewebsites.net", "*", "*")
        {
            cors.SupportsCredentials = true // tried with and without
        };
        config.EnableCors(cors);
    
        // Route registration and other initialization code removed
    }
    
    API选项谓词处理程序注册

    <system.webServer>
      <handlers>
        <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
        <remove name="OPTIONSVerbHandler" />
        <remove name="TRACEVerbHandler" />
        <add name="OPTIONSHandler" path="*" verb="OPTIONS" modules="IsapiModule" scriptProcessor="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" />
        <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
      </handlers>
    </system.webServer>
    
    
    
    

  • 我也遇到了类似的问题,无法找到合适的解决方案。只有Owin cors足以安装。请先检查Owin.cors的软件包

    <package id="Microsoft.Owin" version="3.0.0" targetFramework="net45" />
    <package id="Microsoft.Owin.Cors" version="2.1.0" targetFramework="net45" />
    
    控制器不需要CORS相关属性

       [Authorize]
    public class ContactsController : ApiController
    {
    
        // GET api/<controller>
        public IEnumerable<string> Get()
        {
            return new string[] { "person1", "person2" };
        }
    
        // GET api/<controller>/5
        public string Get(int id)
        {
            return "person" + id;
        }
    
    }]))

    飞行前响应示例:

    Remote Address:127.0.0.1:8888
    Request URL:http://localhost:39725/api/contacts
    Request Method:OPTIONS
    Status Code:200 OK
    Request Headersview source
    Accept:*/*
    Accept-Encoding:gzip, deflate, sdch
    Accept-Language:en-US,en;q=0.8
    Access-Control-Request-Headers:accept, authorization
    Access-Control-Request-Method:GET
    Host:localhost:39725
    Origin:http://localhost:49726
    Proxy-Connection:keep-alive
    Referer:http://localhost:49726/myspa.html
    User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36
    Response Headersview source
    Access-Control-Allow-Credentials:true
    Access-Control-Allow-Headers:authorization
    Access-Control-Allow-Origin:http://localhost:49726
    Content-Length:0
    Date:Fri, 23 Jan 2015 01:10:54 GMT
    Server:Microsoft-IIS/8.0
    X-Powered-By:ASP.NET
    
    已解决(某种程度上)

    这似乎是由部署问题造成的,特别是我最初将应用程序发布到Azure的方式。这两个应用程序最初都是使用Windows身份验证编写的,并部署到标准(即非Azure)web服务器。使用这些技术,这些应用程序工作正常

    根据新的业务需求,我一直在努力将它们迁移到Azure。我遵循的过程是:

  • 按照最初编写的方式,从Visual Studio 2013发布向导将这两个应用程序直接部署/发布到Azure。当然,正如预期的那样,这是坏的,因为他们无法从Azure中与本地Active Directory通信
  • 根据问题末尾所有链接的详细信息,逐步更新代码以删除Windows Auth并替换为Azure AD Auth
  • 手动将应用程序与Azure AD租户关联,以便使用Azure AD门户进行身份验证
  • 在某个时候,我注意到VS发布向导的“设置”选项卡上的“启用组织身份验证”选项,并开始使用它将应用程序与租户关联。因为我已经手动关联了它们,VisualStudio最终为每个应用程序创建了另一个Azure广告应用程序,结果产生了两个

    最后,我们做到了:

    Request OPTIONS /api/items HTTP/1.1 Host: webapi.azurewebsites.net Connection: keep-alive Access-Control-Request-Method: GET Access-Control-Request-Headers: accept, authorization Origin: https://mvcapp.azurewebsites.net User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36 Accept: */* Referer: https://mvcapp.azurewebsites.net/ Response HTTP/1.1 302 Found Content-Length: 504 Location: https://login.windows.net/{authority-guid}/oauth2/authorize?response_type=id_token&redirect_uri=https%3A%2F%2F....etc..etc.%2F&client_id={api-guid}&scope=openid+profile+email&response_mode=form_post&state=...etc... Server: Microsoft-IIS/8.0 X-Powered-By: ASP.NET Set-Cookie: ARRAffinity=4f51...snip....redact....db6d;Path=/;Domain=webapi.azurewebsites.net
  • 已删除使用门户的两个应用程序的所有Azure记录,包括Azure网站本身和Azure广告网站/关联
  • 已将两个应用中的所有代码更改还原回其原始状态
  • 在应用程序中重新实现Azure AD auth(OWIN、adal.js等)
  • 重新发布了两个应用程序,让VS向导处理所有Azure关联
  • 使用新创建的客户端ID更新了Web.config文件和adal.js初始化
  • 再次出版
  • 现在选项飞行前请求不再是302重定向

    相反,它们现在是405方法不允许的,非常类似于。某种程度上说是进步


    即使它仍然无法端到端工作,我还是会留下这个答案(而不是删除这个问题),以防它可能会帮助其他体验Azure 302重定向CORS预飞的人。

    感谢您的回复。您有一个早期版本的Microsoft.Owin.Cors NuGet包(我使用的是3.0.0),并且在Owin和adal.js初始化中使用租户ID而不是租户名称。除此之外,基本上是一样的。希望与希望相反,我换到了先前的包,并尝试使用租户ID。不幸的是,没有骰子。您能否发布工作示例中执行的选项飞行前请求的请求和响应标题?我很想看看它们之间有什么不同,如果有的话。我为选项请求添加了一个例子。您是否收到302的错误?这可能与应用程序的权限设置有关。我还更新了工作示例。感谢您发布标题。有趣。而且,是的,我在这两个应用程序中都配置了Azure AD访问权限。我已经更新了问题,并将该部分添加到“我尝试了什么”部分。您的飞行前响应正在尝试重定向到登录。我认为owin中间件不接受令牌并重定向到登录。您可以使用my cors示例并更改Web.config以尝试您的设置。我在上面提供了github回购链接。观众将是您在angular framework的web应用程序中瞄准的资源。看起来Owin并没有在预飞行中获得令牌。发布的选项请求头都不显示带有承载令牌的授权头,Chrome开发工具也不显示发送的任何请求cookie。我还查看了和的相关源代码。在飞行前的请求中,似乎只检查源代码、方法和头文件。您解决过这个问题吗?我被困在302上,想尽一切办法绕过它。我已经删除了所有内容,并开始了多次。如果您能提供任何帮助,我们将不胜感激。@Isaclevin,302已按上述方式解决。随后的405也在不久后解决了,但我真的不记得它的解决方案是什么。有机会吗