我们是一个致力于 Azure Web 服务的团队。我们想要实现的是拥有一个 JavaScript 前端,它可以与 Azure 中托管的 Java API 应用程序进行通信。
我们使用 Active Directory 进行身份验证。我们已在 Azure 门户中配置了 CORS。
我们已经使用 Swagger Editor 创建了一个 Java 后端,如 this article 中所述。 。我们刚刚改进了这个示例来支持我们自己的数据模型。因此 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 上运行。此外,我们还在 azure 门户的 CORS 中添加了我们的源“http://localhost:8888”。
前端 JavaScript 代码如下所示:
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
);
}]);
但是从前端调用后端,我们在登录租户后收到以下错误:
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.
在 Chrome 的开发者控制台中,我们看到对联系人 API 的四个请求。但都有状态代码“302重定向”。前两个条目包含 header “Access-Control-Allow-Origin: http://localhost:8888”,但其他两个条目不包含此 header 。
编辑:前两个条目之一是 XmlHttpRequest,第二个条目之一是相同的 XmlHttpRequest,但使用 https 而不是 http。
基于此,我们在后端创建了一个新的过滤器来设置 access-control-allow-origin 字段:
@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 开发者控制台的第二个过滤器中看到所有这些 header 。
但是一旦我们将后端部署到 azure,我们就会以某种方式丢失此 header ,并且在从前端访问 api 时再次出现相同的错误:
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.
编辑:正如我所写,有两个 XmlHttpRequest。第二个是https。所以如果在行中
var erg = $http.get('http://<our.backend>.azurewebsites.net/api/contacts')
我将 http 更改为 https,我们遇到了 error()
回调函数。在控制台中我们有输出:
data: User login is required
但正如我之前写的。我们已经登录到我们的租户。那么出了什么问题呢?
最佳答案
var erg = $http.get('http://.azurewebsites.net/api/contacts')
根据代码,您使用 HTTP 协议(protocol)请求服务。当我使用 HTTP 请求受 Azure AD 保护的 Web API 时,我能够重现此问题。 Azure AD 似乎会将 HTTP 重定向到 HTTPS。
在我将服务 URL 更改为 HTTPS 后,问题得到解决。请告诉我是否有帮助。
关于java - CORS 策略拒绝访问 azure 托管的 API 应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40610111/