访问CORS政策拒绝的天蓝色托管API应用 [英] Access to azure hosted API App denied by CORS policy

查看:1049
本文介绍了访问CORS政策拒绝的天蓝色托管API应用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们是一个致力于天蓝网络服务的团队。我们想要实现的是有一个JavaScript前端,可以与我们在Azure中托管的Java API应用程序进行通信。



我们正在使用Active Directory进行身份验证。我们在Azure门户中配置了CORS。



我们使用Swagger Editor创建了一个Java后端,它在本文。我们刚刚推进了这个例子来支持我们自己的数据模型。因此, ApiOriginFilter 类仍然不变:

  @ javax.annotation .Generated(value =class io.swagger.codegen.languages.JavaJerseyServerCodegen,date =2016-11-08T15:40:34.550Z)
public class ApiOriginFilter implements javax.servlet.Filter {
public void doFilter(ServletRequest request,ServletResponse response,
FilterChain chain)throws IOException,ServletException {
HttpServletResponse res =(HttpServletResponse)response;
res.addHeader(Access-Control-Allow-Origin,*);
res.addHeader(Access-Control-Allow-Methods,GET,POST,DELETE,PUT);
res.addHeader(Access-Control-Allow-Headers,Content-Type);
chain.doFilter(request,response);

}

public void destroy(){}

public void init(FilterConfig filterConfig)throws ServletException {}
}

我们的前端运行在本地PC上。此外,我们在天蓝门户中的CORS中添加了来源 http:// localhost:8888 。 p>

前端JavaScript代码如下所示:

  var app = angular。 
.controller('GetDataController',['$ scope','$ http','$ timeout','adalAuthenticationService',function($ demo','adalAngular','ngRoute'范围,$ http,$ timeout,adalAuthenticationService){
$ scope.loggedIn =Logged out;
$ scope.responseData =No Data;
$ scope.loading = ;

$ scope.loginAdal = function(){
adalAuthenticationService.login();
}

$ scope.getData = function(){
$ http.defaults.useXDomain = true;
delete $ http.defaults.headers.common ['X-Requested-With'];

$ scope.loading =加载...;
var erg = $ http.get('http://< our-backend> .azurewebsites.net / api / contacts')
.success(function status,headers,config){
console.log(SUCCESS);
$ scope.loading =Succeeded;
$ scope.loggedIn =LOGGED IN;
$ scope.responseData = data;
})
.error(function(data,status,header,config){
console.log(ERROR);
$ scope.loading =Error
console.log(data:,data);
});
}
}]);

app.config(['$ locationProvider','adalAuthenticationServiceProvider','$ httpProvider','$ routeProvider',function($ locationProvider,adalAuthenticationServiceProvider,$ httpProvider,$ routeProvider){

$ locationProvider.html5Mode({
enabled:true,
requireBase:false,
hashPrefix:'!'
});

var theEndpoints = {
https://< our-backend> .azurewebsites.net / api / contacts:f0f91e4a-ad53-4a4a-ac91-431dd152f386,
};

adalAuthenticationServiceProvider.init(
{
anonymousEndpoints:[],
instance:'https://login.microsoftonline.com/',
tenant:< ; our-tenant> .onmicrosoft.com,
clientId:f6a7ea99-f13b-4673-90b8-ef0c5de9822f,
endpoints:theEndpoints
},
$ httpProvider
);
}]);

但是从前端调用后端,我们在登录到我们的租户后会收到以下错误:


XMLHttpRequest无法加载 https:// [our-backend] .azurewebsites.net / api / contacts 。从 https:// [我们的后端] .azurewebsites.net / api / contacts重定向'到
' https://login.windows。 net / 12141bed-36f0-4fc6-b70c-
43483f616eb7 / oauth2 / autho ...
%2Fapi%2Fcontacts%23& nonce = 7658b7c8155b4b278f2f1447d4b77e47_20161115124144'
已被CORS政策阻止:在请求的资源上不存在Access-Control-Allow-Origin
头。


在Chrome的开发者控制台中,我们看到四个联系人api的请求。但都具有状态代码302重定向。前两个条目包含标题Access-Control-Allow-Origin: http:// localhost:8888 ,但其他两个条目包含此标题。



EDIT:前两个条目之一是XmlHttpRequest,其中一个第二个条目是相同的XmlHttpRequest,但使用 https 而不是 http



在此基础上,我们在后端中创建了一个新的过滤器,以设置访问控制允许原始字段:

  @Provider 
public class CrossOriginFilter implements ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext containerRequestContext,ContainerResponseContext containerResponseContext)throws IOException {
containerResponseContext.getHeaders()。add(Access-Control-Allow-Origin,*);
containerResponseContext.getHeaders()。add(Access-Control-Allow-Headers,origin,content-type,accept,authorization);
containerResponseContext.getHeaders()。add(Access-Control-Allow-Credentials,true);
containerResponseContext.getHeaders()。add(Access-Control-Allow-Methods,GET,POST,PUT,DELETE,OPTIONS,HEAD);
containerResponseContext.getHeaders()。add(Access-Control-Max-Age,1209600);
}
}

并从ApiOriginFilter中删除这三个字段:

  res.addHeader(Access-Control-Allow-Origin,*); 
res.addHeader(Access-Control-Allow-Methods,GET,POST,DELETE,PUT);
res.addHeader(Access-Control-Allow-Headers,Content-Type);

现在,如果我们在本地运行后端 Chrome开发人员控制台中的第2个筛选器。



但是一旦我们将后端部署到azure,我们从前端访问api时就会丢失这个头部,并且会有同样的错误:


XMLHttpRequest无法加载 https :// [our-backend] .azurewebsites.net / api / contacts 。从 https:// [我们的后端] .azurewebsites.net / api / contacts重定向'到
' https://login.windows。 net / 12141bed-36f0-4fc6-b70c-
43483f616eb7 / oauth2 / autho ...
%2Fapi%2Fcontacts%23& nonce = 7658b7c8155b4b278f2f1447d4b77e47_20161115124144'
已被CORS政策阻止:在请求的资源上不存在Access-Control-Allow-Origin
头。原因'null'是
因此不允许访问。


编辑:我写的是有两个XmlHttpRequests。第二个是 https 。所以如果在行

  var erg = $ http.get('http://< our.backend> .azurewebsites .net / api / contacts')

我将 http 更改为 https ,我们遇到了错误()回调函数。在控制台中我们有输出:


data:需要用户登录


但正如我之前写的。我们已经登录到我们的租户。

解决方案


var erg = $ http.get('http: /.azurewebsites.net/api/contacts')


根据该代码,您使用 HTTP 协议。当我通过 HTTP 请求受Azure AD保护的Web API时,我可以重现此问题。看来Azure AD会将 HTTP 重定向到 HTTPS



strong> HTTPS ,则问题已修复。请让我知道这是否有帮助。


We are a team working on azure web services. What we want to achieve is having a JavaScript frontend which can communicate with our Java API App hosted in Azure.

We are using Active Directory for Authentication. And we have configured CORS within the Azure portal.

We have created a Java backend with Swagger Editor as it is described in this article. We have just advanced this example to support our own data model. So also the ApiOriginFilter class is still unchanged:

@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaJerseyServerCodegen", date = "2016-11-08T15:40:34.550Z")
public class ApiOriginFilter implements javax.servlet.Filter {
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        HttpServletResponse res = (HttpServletResponse) response;
        res.addHeader("Access-Control-Allow-Origin", "*");
        res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
        res.addHeader("Access-Control-Allow-Headers", "Content-Type");
        chain.doFilter(request, response);

    }

    public void destroy() {}

    public void init(FilterConfig filterConfig) throws ServletException {}
}

Our frontend runs on a local PC. So furthermore, we added our origin "http://localhost:8888" in the CORS in the azure portal.

The frontend JavaScript code looks like this:

var app = angular.module('demo', ['AdalAngular', 'ngRoute'])
    .controller('GetDataController', ['$scope', '$http', '$timeout', 'adalAuthenticationService', function($scope, $http, $timeout, adalAuthenticationService) {
        $scope.loggedIn = "Logged out";
        $scope.responseData = "No Data";
        $scope.loading = "";

        $scope.loginAdal = function(){
          adalAuthenticationService.login();
        }

        $scope.getData = function(){            
          $http.defaults.useXDomain = true;
          delete $http.defaults.headers.common['X-Requested-With'];

          $scope.loading = "loading...";
          var erg = $http.get('http://<our-backend>.azurewebsites.net/api/contacts')
            .success(function (data, status, headers, config) {
                console.log("SUCCESS");
                $scope.loading = "Succeeded";
                $scope.loggedIn = "LOGGED IN";
                $scope.responseData = data;     
            })
            .error(function (data, status, header, config) {
                console.log("ERROR");
                $scope.loading = "Error";
                console.log("data: ", data);
            });
        }
    }]);

    app.config(['$locationProvider', 'adalAuthenticationServiceProvider', '$httpProvider', '$routeProvider', function($locationProvider, adalAuthenticationServiceProvider, $httpProvider, $routeProvider) {

        $locationProvider.html5Mode({
          enabled: true,
          requireBase: false,
          hashPrefix: '!'
        });

        var theEndpoints = {
          "https://<our-backend>.azurewebsites.net/api/contacts": "f0f91e4a-ad53-4a4a-ac91-431dd152f386", 
        };

        adalAuthenticationServiceProvider.init(
        {
            anonymousEndpoints: [],
            instance: 'https://login.microsoftonline.com/',
            tenant: "<our-tenant>.onmicrosoft.com", 
            clientId: "f6a7ea99-f13b-4673-90b8-ef0c5de9822f", 
            endpoints: theEndpoints 
        },
        $httpProvider 
        );
}]);

But calling the backend from the frontend we get the following error after logging in into our tenant:

XMLHttpRequest cannot load https://[our-backend].azurewebsites.net/api/contacts. Redirect from 'https://[our-backend].azurewebsites.net/api/contacts' to 'https://login.windows.net/12141bed-36f0-4fc6-b70c- 43483f616eb7/oauth2/autho… %2Fapi%2Fcontacts%23&nonce=7658b7c8155b4b278f2f1447d4b77e47_20161115124144' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.

In Chrome's developer console we see four requests to our contacts api. But all have the status code "302 Redirect". The first two entries contain the header "Access-Control-Allow-Origin:http://localhost:8888" but the other two entries do not contain this header.

EDIT: One of the first two entries is an XmlHttpRequest and one of the second entries is the same XmlHttpRequest but with https instead of http.

Based on this, we created a new filter in our backend to set the access-control-allow-origin field:

@Provider
public class CrossOriginFilter implements ContainerResponseFilter {
    @Override
    public void filter(ContainerRequestContext containerRequestContext, ContainerResponseContext containerResponseContext) throws IOException {
        containerResponseContext.getHeaders().add("Access-Control-Allow-Origin", "*");
        containerResponseContext.getHeaders().add("Access-Control-Allow-Headers", "origin, content-type, accept, authorization");
        containerResponseContext.getHeaders().add("Access-Control-Allow-Credentials", "true");
        containerResponseContext.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD");
        containerResponseContext.getHeaders().add("Access-Control-Max-Age", "1209600");    
    }
}

and deleted these three fields from ApiOriginFilter:

res.addHeader("Access-Control-Allow-Origin", "*");
res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
res.addHeader("Access-Control-Allow-Headers", "Content-Type");

Now if we run the backend locally, we see all these headers from the 2nd filter in Chrome's developer console.

But as soon as we deploy the backend to azure we loose this headers somehow and again have the same error when accessing the api from the frontend:

XMLHttpRequest cannot load https://[our-backend].azurewebsites.net/api/contacts. Redirect from 'https://[our-backend].azurewebsites.net/api/contacts' to 'https://login.windows.net/12141bed-36f0-4fc6-b70c- 43483f616eb7/oauth2/autho… %2Fapi%2Fcontacts%23&nonce=7658b7c8155b4b278f2f1447d4b77e47_20161115124144' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.

EDIT: As I wrote there are two XmlHttpRequests made. And the second one is https. So If in the line

var erg = $http.get('http://<our.backend>.azurewebsites.net/api/contacts')

I change http to https we run into the error() callback function. And in the console we have the output:

data: User login is required

But as I wrote before. We are already logged in to our tenant. So what is going wrong?

解决方案

var erg = $http.get('http://.azurewebsites.net/api/contacts')

Based on the code, you were request the service with HTTP protocol. I am able to reproduce this issue when I request the web API which protected by Azure AD with the HTTP. It seems that the Azure AD will redirect the HTTP to HTTPS.

After I change the service URL with HTTPS, the issue was fixed. Please let me know whether it is helpful.

这篇关于访问CORS政策拒绝的天蓝色托管API应用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆