问题
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?
回答1:
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.
来源:https://stackoverflow.com/questions/40610111/access-to-azure-hosted-api-app-denied-by-cors-policy