AngularJS $http、CORS 和 Jersey 的基本身份验证
AngularJS $http, CORS and Basic authentication with Jersey
我正在学习AngularJS。我已经使用 CORS
和基本身份验证创建了示例项目。我的服务器端代码是 Jersey Rest。但我仍然收到 403 禁止错误。我不明白。我错过了什么吗?我的代码如下。请帮我解决一下。
服务器代码--
/*
* This is the controller level Code to get all UserlogInHistoryAngular
* information
*/
@GET
@Path("/getall")
@Produces({
MediaType.APPLICATION_XML,
MediaType.APPLICATION_JSON
})
public Response getAllUserLogInHistoryAngular() {
log.info("Controller layer for Get All UserlogInHistory");
UserLoginHistoryService userLogInHistoryService = new UserLoginHistoryService();
GenericEntity < List < UserLogInHistory >> userLoginHistory = new GenericEntity < List < UserLogInHistory >> (
userLogInHistoryService.getAllUserlogInHisotry()) {};
return Response
.status(200)
.entity(userLoginHistory)
.header("Access-Control-Allow-Credentials", true)
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods",
"GET, POST, DELETE, PUT, OPTIONS")
.header("Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Authorization, X-CSRF-Token, Accept-Version, Content-Length, Content-MD5, Date, X-Api-Version, X-File-Name")
.allow("OPTIONS").build();
}
}
AngularJS代码--
var myapp = angular
.module('myapp', ['angularUtils.directives.dirPagination']);
myapp.config(function($httpProvider) {
//Enable cross domain calls
$httpProvider.defaults.withCredentials = true;
$httpProvider.defaults.useXDomain = true;
});
myapp.controller('customerController', function($scope, $http) {
var encodingstring = window.btoa("numery" + ":" + "password");
console.log(encodingstring);
$http({
withCredentials: true,
headers: {
'Authorization': 'Basic ' + encodingstring,
'Content-Type': 'application/json; charset=utf-8'
},
method: "GET",
url: "http://localhost:8080/userloginhistoryapi/rest/secured/userloginhistory/getall"
}).then(function(response) {
$scope.lstUser = response.data;
//$log.info(response);
console.log(response.data);
console.log($scope.lstUser);
})
$scope.sortColumn = "name";
$scope.reverseSort = false;
$scope.sortData = function(column) {
$scope.reverseSort = ($scope.sortColumn == column) ? !$scope.reverseSort : false;
$scope.sortColumn = column;
};
$scope.getSortColumn = function(column) {
if ($scope.sortColumn == column) {
return $scope.reverseSort ? 'arrow-down' : 'arrow-up';
}
return '';
};
function getSelectedIndex(id) {
for (var i = 0; i < $scope.listCustomers.length; i++)
if ($scope.listCustomers[i].id == id)
return i
return -1;
};
错误--
angular.js:13018 OPTIONS http://localhost:8080/userloginhistoryapi/rest/secured/userloginhistory/getall 403 (Forbidden)
(anonymous) @ angular.js:13018
sendReq @ angular.js:12744
serverRequest @ angular.js:12485
processQueue @ angular.js:17396
(anonymous) @ angular.js:17444
$digest @ angular.js:18557
$apply @ angular.js:18945
bootstrapApply @ angular.js:1939
invoke @ angular.js:5108
doBootstrap @ angular.js:1937
bootstrap @ angular.js:1957
angularInit @ angular.js:1842
(anonymous) @ angular.js:35431
trigger @ angular.js:3491
(index):1 Failed to load http://localhost:8080/userloginhistoryapi/rest/secured/userloginhistory/getall: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8081' is therefore not allowed access. The response had HTTP status code 403.
angular.js:15018 Possibly unhandled rejection: {"data":null,"status":-1,"config":{"method":"GET","transformRequest":[null],"transformResponse":[null],"jsonpCallbackParam":"callback","withCredentials":true,"headers":{"Authorization":"Basic bnVtZXJ5OnBhc3N3b3Jk","Accept":"application/json, text/plain, */*"},"url":"http://localhost:8080/userloginhistoryapi/rest/secured/userloginhistory/getall"},"statusText":"","xhrStatus":"error"}
(anonymous) @ angular.js:15018
(anonymous) @ angular.js:11302
processChecks @ angular.js:17428
$digest @ angular.js:18557
$apply @ angular.js:18945
done @ angular.js:12799
completeRequest @ angular.js:13056
requestError @ angular.js:12972
error (async)
(anonymous) @ angular.js:12985
sendReq @ angular.js:12744
serverRequest @ angular.js:12485
processQueue @ angular.js:17396
(anonymous) @ angular.js:17444
$digest @ angular.js:18557
$apply @ angular.js:18945
bootstrapApply @ angular.js:1939
invoke @ angular.js:5108
doBootstrap @ angular.js:1937
bootstrap @ angular.js:1957
angularInit @ angular.js:1842
(anonymous) @ angular.js:35431
trigger @ angular.js:3491
VM2032:185 [CodeLive] HTTP detected: Connecting using WS
VM2032:109 [CodeLive] Connected to CodeLive at ws://127.0.0.1:42529
bundle.js:10 license url https://www.genuitec.com/go/webclipse-buy-now
事情是这样的。 CORS Preflight request 是一个 OPTIONS
请求。此请求发生在 之前 实际请求。它检查服务器以查看是否允许该请求。作为对预检请求的响应,服务器应该发回 Access-Control-X-X
header,就像您在 getAllUserLogInHistoryAngular
方法中一样。
那么在预检期间您的案例发生了什么,它命中了基本身份验证过滤器并自动被拒绝而不添加 CORS 响应 headers。您将 CORS 响应 headers 放在资源方法中没有任何作用,也没有用。通常应该在过滤器中处理 CORS,以便它在访问资源方法之前处理所有请求。
这是您应该做的。就像您对 Basic Auth 所做的那样,使用 ContainerRequestFilter
来处理 CORS。您希望在 Auth 过滤器之前调用此过滤器,因为 CORS 预检不关心身份验证,它不会随请求发送身份验证凭据。在此过滤器中,您应该检查它是否是 CORS 预检请求。通常这可以通过检查 OPTIONS
方法和 Origin
header 的存在来完成。如果是预检,则中止请求并在 ContainerResponseFilter
中添加 CORS headers。它可能看起来像
@Provider
@PreMatching
public class CorsFilter implements ContainerRequestFilter, ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext request) throws IOException {
if (isPreflightRequest(request)) {
request.abortWith(Response.ok().build());
return;
}
}
private static boolean isPreflightRequest(ContainerRequestContext request) {
return request.getHeaderString("Origin") != null
&& request.getMethod().equalsIgnoreCase("OPTIONS");
}
@Override
public void filter(ContainerRequestContext request, ContainerResponseContext response)
throws IOException {
if (request.getHeaderString("Origin") == null) {
return;
}
if (isPreflightRequest(request)) {
response.getHeaders().add("Access-Control-Allow-Credentials", "true");
response.getHeaders().add("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD");
response.getHeaders().add("Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Authorization, X-CSRF-Token, " +
"Accept-Version, Content-Length, Content-MD5, Date, X-Api-Version, X-File-Name");
}
response.getHeaders().add("Access-Control-Allow-Origin", "*");
}
}
注意它是一个 @PreMatching
过滤器,这将导致它在您的 Auth 过滤器之前被调用(假设该过滤器不是 pre-matching 过滤器,在这种情况下您还应该使用 @Priority
注释)。
这个过滤器的作用是检查请求是否是预检请求,如果是,它会用 200 中止整个请求,这会导致请求跳过资源方法,跳过所有其他请求过滤器在它之后,跳转到响应过滤器。在响应过滤器中,我们通过检查我们之前设置的 属性 来检查它是否是预检。如果是,那么我们设置 CORS 响应 headers。如果您想了解有关 CORS 的更多信息以及有关此特定过滤器实现的更多信息,请查看 this post.
所以这不是将要发生的事情的流程
Client Browser Server
------ ------- ------
Request endpoint -------> Remembers request -------> Sends back CORS
But first sends response headers
CORS preflight from CorsFilter
|
Grabs original <----------------+
request, sends it
|
+----------------> Skips CorsFilter,
Goes to Auth filter,
Goes to resource
Sends resource response
|
Handle response <------- Receives response <----------------+
Gives it to client
我正在学习AngularJS。我已经使用 CORS
和基本身份验证创建了示例项目。我的服务器端代码是 Jersey Rest。但我仍然收到 403 禁止错误。我不明白。我错过了什么吗?我的代码如下。请帮我解决一下。
服务器代码--
/*
* This is the controller level Code to get all UserlogInHistoryAngular
* information
*/
@GET
@Path("/getall")
@Produces({
MediaType.APPLICATION_XML,
MediaType.APPLICATION_JSON
})
public Response getAllUserLogInHistoryAngular() {
log.info("Controller layer for Get All UserlogInHistory");
UserLoginHistoryService userLogInHistoryService = new UserLoginHistoryService();
GenericEntity < List < UserLogInHistory >> userLoginHistory = new GenericEntity < List < UserLogInHistory >> (
userLogInHistoryService.getAllUserlogInHisotry()) {};
return Response
.status(200)
.entity(userLoginHistory)
.header("Access-Control-Allow-Credentials", true)
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods",
"GET, POST, DELETE, PUT, OPTIONS")
.header("Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Authorization, X-CSRF-Token, Accept-Version, Content-Length, Content-MD5, Date, X-Api-Version, X-File-Name")
.allow("OPTIONS").build();
}
}
AngularJS代码--
var myapp = angular
.module('myapp', ['angularUtils.directives.dirPagination']);
myapp.config(function($httpProvider) {
//Enable cross domain calls
$httpProvider.defaults.withCredentials = true;
$httpProvider.defaults.useXDomain = true;
});
myapp.controller('customerController', function($scope, $http) {
var encodingstring = window.btoa("numery" + ":" + "password");
console.log(encodingstring);
$http({
withCredentials: true,
headers: {
'Authorization': 'Basic ' + encodingstring,
'Content-Type': 'application/json; charset=utf-8'
},
method: "GET",
url: "http://localhost:8080/userloginhistoryapi/rest/secured/userloginhistory/getall"
}).then(function(response) {
$scope.lstUser = response.data;
//$log.info(response);
console.log(response.data);
console.log($scope.lstUser);
})
$scope.sortColumn = "name";
$scope.reverseSort = false;
$scope.sortData = function(column) {
$scope.reverseSort = ($scope.sortColumn == column) ? !$scope.reverseSort : false;
$scope.sortColumn = column;
};
$scope.getSortColumn = function(column) {
if ($scope.sortColumn == column) {
return $scope.reverseSort ? 'arrow-down' : 'arrow-up';
}
return '';
};
function getSelectedIndex(id) {
for (var i = 0; i < $scope.listCustomers.length; i++)
if ($scope.listCustomers[i].id == id)
return i
return -1;
};
错误--
angular.js:13018 OPTIONS http://localhost:8080/userloginhistoryapi/rest/secured/userloginhistory/getall 403 (Forbidden)
(anonymous) @ angular.js:13018
sendReq @ angular.js:12744
serverRequest @ angular.js:12485
processQueue @ angular.js:17396
(anonymous) @ angular.js:17444
$digest @ angular.js:18557
$apply @ angular.js:18945
bootstrapApply @ angular.js:1939
invoke @ angular.js:5108
doBootstrap @ angular.js:1937
bootstrap @ angular.js:1957
angularInit @ angular.js:1842
(anonymous) @ angular.js:35431
trigger @ angular.js:3491
(index):1 Failed to load http://localhost:8080/userloginhistoryapi/rest/secured/userloginhistory/getall: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8081' is therefore not allowed access. The response had HTTP status code 403.
angular.js:15018 Possibly unhandled rejection: {"data":null,"status":-1,"config":{"method":"GET","transformRequest":[null],"transformResponse":[null],"jsonpCallbackParam":"callback","withCredentials":true,"headers":{"Authorization":"Basic bnVtZXJ5OnBhc3N3b3Jk","Accept":"application/json, text/plain, */*"},"url":"http://localhost:8080/userloginhistoryapi/rest/secured/userloginhistory/getall"},"statusText":"","xhrStatus":"error"}
(anonymous) @ angular.js:15018
(anonymous) @ angular.js:11302
processChecks @ angular.js:17428
$digest @ angular.js:18557
$apply @ angular.js:18945
done @ angular.js:12799
completeRequest @ angular.js:13056
requestError @ angular.js:12972
error (async)
(anonymous) @ angular.js:12985
sendReq @ angular.js:12744
serverRequest @ angular.js:12485
processQueue @ angular.js:17396
(anonymous) @ angular.js:17444
$digest @ angular.js:18557
$apply @ angular.js:18945
bootstrapApply @ angular.js:1939
invoke @ angular.js:5108
doBootstrap @ angular.js:1937
bootstrap @ angular.js:1957
angularInit @ angular.js:1842
(anonymous) @ angular.js:35431
trigger @ angular.js:3491
VM2032:185 [CodeLive] HTTP detected: Connecting using WS
VM2032:109 [CodeLive] Connected to CodeLive at ws://127.0.0.1:42529
bundle.js:10 license url https://www.genuitec.com/go/webclipse-buy-now
事情是这样的。 CORS Preflight request 是一个 OPTIONS
请求。此请求发生在 之前 实际请求。它检查服务器以查看是否允许该请求。作为对预检请求的响应,服务器应该发回 Access-Control-X-X
header,就像您在 getAllUserLogInHistoryAngular
方法中一样。
那么在预检期间您的案例发生了什么,它命中了基本身份验证过滤器并自动被拒绝而不添加 CORS 响应 headers。您将 CORS 响应 headers 放在资源方法中没有任何作用,也没有用。通常应该在过滤器中处理 CORS,以便它在访问资源方法之前处理所有请求。
这是您应该做的。就像您对 Basic Auth 所做的那样,使用 ContainerRequestFilter
来处理 CORS。您希望在 Auth 过滤器之前调用此过滤器,因为 CORS 预检不关心身份验证,它不会随请求发送身份验证凭据。在此过滤器中,您应该检查它是否是 CORS 预检请求。通常这可以通过检查 OPTIONS
方法和 Origin
header 的存在来完成。如果是预检,则中止请求并在 ContainerResponseFilter
中添加 CORS headers。它可能看起来像
@Provider
@PreMatching
public class CorsFilter implements ContainerRequestFilter, ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext request) throws IOException {
if (isPreflightRequest(request)) {
request.abortWith(Response.ok().build());
return;
}
}
private static boolean isPreflightRequest(ContainerRequestContext request) {
return request.getHeaderString("Origin") != null
&& request.getMethod().equalsIgnoreCase("OPTIONS");
}
@Override
public void filter(ContainerRequestContext request, ContainerResponseContext response)
throws IOException {
if (request.getHeaderString("Origin") == null) {
return;
}
if (isPreflightRequest(request)) {
response.getHeaders().add("Access-Control-Allow-Credentials", "true");
response.getHeaders().add("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD");
response.getHeaders().add("Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Authorization, X-CSRF-Token, " +
"Accept-Version, Content-Length, Content-MD5, Date, X-Api-Version, X-File-Name");
}
response.getHeaders().add("Access-Control-Allow-Origin", "*");
}
}
注意它是一个 @PreMatching
过滤器,这将导致它在您的 Auth 过滤器之前被调用(假设该过滤器不是 pre-matching 过滤器,在这种情况下您还应该使用 @Priority
注释)。
这个过滤器的作用是检查请求是否是预检请求,如果是,它会用 200 中止整个请求,这会导致请求跳过资源方法,跳过所有其他请求过滤器在它之后,跳转到响应过滤器。在响应过滤器中,我们通过检查我们之前设置的 属性 来检查它是否是预检。如果是,那么我们设置 CORS 响应 headers。如果您想了解有关 CORS 的更多信息以及有关此特定过滤器实现的更多信息,请查看 this post.
所以这不是将要发生的事情的流程
Client Browser Server
------ ------- ------
Request endpoint -------> Remembers request -------> Sends back CORS
But first sends response headers
CORS preflight from CorsFilter
|
Grabs original <----------------+
request, sends it
|
+----------------> Skips CorsFilter,
Goes to Auth filter,
Goes to resource
Sends resource response
|
Handle response <------- Receives response <----------------+
Gives it to client