CORS 预检请求在 Azure 托管 Web API 中通过 302 重定向进行响应

2023-12-20

设想:

我有两个分别托管在 Windows Azure 上的 ASP.NET Web 应用程序,并且都与同一个 Azure Active Directory 租户关联:

  1. 具有 AngularJS SPA 前端的 MVC 应用程序和adal.js https://github.com/AzureAD/azure-activedirectory-library-for-js用于在客户端上处理 Azure AD 身份验证的库。

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

Problem:

当 Angular 引导客户端应用程序时,页面在经过 oauth 重定向到正确的身份验证机构后正确加载,并且 adal.js 库正确检索并存储每个应用程序的不同令牌(通过检查 Chrome 开发工具中的资源/会话存储选项卡进行验证)。但是,当客户端应用程序尝试访问或更新 API 中的任何数据时,CORS 预检请求将通过 302 重定向响应到身份验证机构,这会导致控制台中出现以下错误:

XMLHttpRequest 无法加载https://webapi.azurewebsites.net/api/items https://webapi.azurewebsites.net/api/items。 请求被重定向到 'https://login.windows.net/ https://login.windows.net/{authority-guid}/oauth2/authorize?response_type=id_token&redirect_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  

我所做的/尝试过的

  1. 确保 Azure AD 租户允许 OAuth2 隐式流,如所述here http://www.cloudidentity.com/blog/2014/10/28/adal-javascript-and-angularjs-deep-dive/和其他地方。
  2. 确保 API公开访问权限 https://msdn.microsoft.com/en-us/library/azure/dn132599.aspx#BKMK_Exposing并且 MVC/SPA寄存器访问 https://msdn.microsoft.com/en-us/library/azure/dn132599.aspx#BKMK_Accessing使用这些公开的权限。
  3. 在 API 的 web.config 中显式添加了 OPTIONS 动词处理程序(见下文)。
  4. 在 API 服务器、OWIN 本身以及 EnableCorsAttribute 上使用了启用 CORS 的各种组合(见下文)。

问题

有没有办法让与 Azure AD 租户关联的 Web API 不重定向 CORS 预检请求? 我是否缺少 adal.js 库和/或 OWIN 启动代码中的一些初始化设置(见下文)? Azure 门户中是否有允许 OPTIONS 请求通过 OWIN 管道的设置?

相关代码:

adal.js 初始化

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);
    }
]);

OWIN中间件初始化

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);
}

WebApiConfig 初始化

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>

相关资源

我曾经尝试过以下(以及更多)论坛和博客文章以及 github 示例代码中的几乎所有可以想象到的组合。

  1. ADAL JavaScript 和 AngularJS – 深入探讨 http://www.cloudidentity.com/blog/2014/10/28/adal-javascript-and-angularjs-deep-dive/
  2. 使用 Azure Active Directory、Owin 中间件和 ADAL 保护 ASP.NET Web API 2 http://bitoftech.net/2014/09/12/secure-asp-net-web-api-2-azure-active-directory-owin-middleware-adal/
  3. 使用 ASP.NET Web API 2、Owin 和 Identity 进行基于令牌的身份验证 http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity/
  4. AzureADSamples/SinglePageApp-DotNet (github) https://github.com/AzureADSamples/SinglePageApp-DotNet
  5. AngularJSCORS (github) https://github.com/matvelloso/AngularJSCORS
  6. 如何在WebAPI 2中进行CORS身份验证? https://stackoverflow.com/q/20079813/51242
  7. WebApi 上的 AngularJS 和 OWIN 身份验证 https://stackoverflow.com/q/24461605/51242

我遇到了类似的问题来找出合适的软件包。只需要设置 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" />

处理程序的 Web 配置选项:

<system.webServer>
<handlers>
  <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
  <remove name="OPTIONSVerbHandler" />
  <remove name="TRACEVerbHandler" />
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>

您在 owin 配置中指定 cors 选项是正确的。

 public void ConfigureAuth(IAppBuilder app)
    {
        app.UseWindowsAzureActiveDirectoryBearerAuthentication(
            new WindowsAzureActiveDirectoryBearerAuthenticationOptions
            {
                Audience = ConfigurationManager.AppSettings["ida:Audience"],
                Tenant = ConfigurationManager.AppSettings["ida:Tenant"]

            });
        app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
    }

控制器不需要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;
    }

WebAPIConfig 不需要 CORS 相关条目。

工作示例在这里:https://github.com/omercs/corsapisample https://github.com/omercs/corsapisample

您可以使用以下代码在您的应用程序中进行测试:

app.factory('contactService', ['$http', function ($http) {
var serviceFactory = {};

var _getItems = function () {
    $http.defaults.useXDomain = true;
    delete $http.defaults.headers.common['X-Requested-With'];
    return $http.get('http://yourhostedpage/api/contacts');
};

serviceFactory.getItems = _getItems;

return serviceFactory;

}]);

飞行前响应示例:

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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CORS 预检请求在 Azure 托管 Web API 中通过 302 重定向进行响应 的相关文章

  • 使用 ng-blur 和 ui-sref 无法按预期工作

    我有一个带有自定义下拉结果面板的搜索字段 在其中输入单词或聚焦时会显示该面板 所以我的 html 看起来像这样 div class input group div
  • 如何在 AngularJS 中滚动到页面顶部?

    我想在使用 angularjs 获得 ajax 调用响应后滚动到页面顶部 基本上 我在页面顶部显示警报消息 并且希望在收到 ajax 响应时将警报消息集中显示 Thanks 您可以使用 window scrollTo x y where x
  • 共享 Owin Cookie 身份验证和基于旧版表单身份验证 cookie

    在我们公司 我们拥有大量使用 Asp net Web Forms 4 0 构建的应用程序 这些应用程序使用表单身份验证作为单点登录身份验证 配置如下
  • AngularJS - 在等待数据/数据计算时加载图标

    我有一个简单的 Angular http get app factory countriesService function http return getCountryData function done http get resourc
  • “move(-1)”作为 AngularJS 表达式有什么问题吗?

    我收到此错误 parse ueoe Unexpected end of expression move 从这段代码来看
  • 将 Angularjs 动态绑定到新创建的 html 元素

    我有一个带有多个选项卡的选项卡页面 一旦单击调用服务即可返回一些数据 其中一些数据返回 html 表单并且非常随机 我想收集输入的这些值并通过服务将数据发送回服务器 我遇到的问题是我无法从我动态创建的 html 中的输入元素获取数据 我创建
  • 从 swagger UI 将 Jwt 令牌作为不记名令牌传递到标头中不起作用

    我正在生成 jwt 令牌 Web api 核心应用程序 在应用程序中 我使用 swagger 并应用了不记名令牌身份验证 但是当我尝试从 swagger UI 传递不记名令牌时 我收到 401 错误 请有人帮助我解决这个问题 service
  • Azure DocumentDB 所有者资源不存在

    我有同样的错误 icrosoft Azure Documents DocumentClientException Message Errors Owner resource does not exit 这是我的情况 当我将 web 应用程序
  • 删除 Azure 服务总线中的死主题

    我试图在这个问题上做足功课 但我所做的任何搜索都没有让我更接近答案 最近的命中是检测并删除 Azure 服务总线上的孤立队列 主题或订阅 https stackoverflow com questions 12334838 detect a
  • 如何从 URL 字符串中删除某些参数?

    我有这个var存储表示充满参数的 URL 的字符串 我正在使用 AngularJS 我不确定是否有任何有用的模块 或者可能使用纯 JavaScript 来删除不需要的 URL 参数而无需使用正则表达式 例如我需要删除 month 05并且
  • 通过隔离范围进行 AngularJS 基于事件的通信

    在 AngularJS 中 一个指令如何使用基于事件的通信 emit broadcast and on 与另一个具有隔离范围的指令进行通信 我创建了两个指令 当从第二个指令中删除隔离范围时 第一个指令能够使用emit 与第二个指令成功通信
  • Azure Functions [JavaScript / Node.js] - HTTP 调用,良好实践

    从我的 Azure 函数 在 Node js 中运行 由 EventHub 消息触发 中 我想向某个外部页面发出发布请求 就像是 module exports function context eventHubMessages var ht
  • 调整离子卡中的图像大小

    我想显示一组图像 并在下面说明 我选择使用 Ionic 卡 我得到这个结果 第一张图片 虽然我想保留现在的相同布局 并添加描述 这是我的代码
  • 有没有办法以编程方式更改 Azure 函数触发器类型。

    看起来 Azure 函数的 zip 文件中的 function json 定义了 Az func 的触发器 是否可以通过编程方式将触发器从基于计时器的触发器更改为基于事件的触发器 意思是 我可以在本地计算机上运行一个 python 应用程序
  • 逻辑应用的 IP 白名单

    如何将逻辑应用的 IP 地址列入白名单 由逻辑应用程序调用的服务 使用 HTTP 操作 但该服务需要白名单才能调用 那么 如何将逻辑APP列入白名单呢 我们可以使用Azure API管理进行白名单 它发布逻辑App 因为api管理提供静态I
  • ASP.NET Web Api 的事件发布者

    我已经开始使用微服务 我需要创建一个事件发布机制 我计划使用 Amazon SQS 这个想法很简单 我将事件存储在与聚合相同的事务中的数据库中 如果用户更改他的电子邮件 事件UserChangedEmail将被存储在数据库中 我还有事件处理
  • azure 和 google 上的自定义联合代理

    azure 和 google 中的 aws 上的自定义联合代理可以替代什么 在AWS中 我可以创建一个允许联合用户登录并访问这样的资源的url https docs aws amazon com IAM latest UserGuide i
  • 通过ajax执行后期操作时如何克服CORS重定向问题?

    我可以通过外部登录表单中的 post 方法类型提交表单来登录 roundcube 实例 托管在另一台服务器上 我收到此错误 通过 ajax 签名时 XMLHttpRequest 无法加载https 192 168 0 7 mail http
  • ChangeState 之后重置/卸载控制器(调用注销)。 AngularJS

    我正在创建一个应用程序 用户可以从 Facebook 或 Twitter 登录 登录后 用户将被定向到某个主页 在这里 控制器加载并调用我的初始函数 该函数加载特定于该用户的数据 当用户单击 注销 时 令牌将被清除 用户将被定向到登录页面
  • 如何将 tfvc 迁移到 Git(包括历史记录)

    我们计划从 tfvc 迁移到 Git 版本控制 我们有一些 GB 的代码和数千个变更集 我阅读了一些文章并浏览了 Microsoft 文档 发现了 2 个选项 提示迁移 我可以在其中使用 Azure Devops 内置工具 导入存储库 它有

随机推荐