AngularJS $http、CORS 和 Jersey 的基本身份验证
Posted
技术标签:
【中文标题】AngularJS $http、CORS 和 Jersey 的基本身份验证【英文标题】:AngularJS $http, CORS and Basic authentication with Jersey 【发布时间】:2019-01-07 09:20:56 【问题描述】:我正在学习 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
【问题讨论】:
您是否检查过任何 REST 客户端(如 Postman)中的服务是否可以正常使用凭据? 您的基本身份验证在哪里进行? 服务在 PostMan 和 SoapUI 中运行良好。我已经检查了两者。我使用 ContainerRequestFilter 进行基本身份验证 【参考方案1】:所以这就是正在发生的事情。 CORS Preflight request 是一个 OPTIONS
请求。此请求在实际请求之前发生。它与服务器检查以查看请求是否被允许。为了响应预检请求,服务器应该像在 getAllUserLogInHistoryAngular
方法中一样发回 Access-Control-X-X
标头。
因此,在预检期间,您的情况发生了什么,即它命中了基本身份验证过滤器并在不添加 CORS 响应标头的情况下自动被拒绝。您将 CORS 响应标头放在资源方法中什么也没做,也没用。通常,CORS 应在过滤器中处理,以便在访问资源方法之前处理所有请求。
这是你应该做的。就像您对 Basic Auth 所做的一样,使用 ContainerRequestFilter
来处理 CORS。您希望在 Auth 过滤器之前调用此过滤器,因为 CORS 预检不关心身份验证,它不会随请求发送身份验证凭据。在此过滤器中,您应该检查它是否是 CORS 预检请求。通常这可以通过检查OPTIONS
方法和Origin
标头的存在来完成。如果是预检,则中止请求并在ContainerResponseFilter
中添加 CORS 标头。它可能看起来像
@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
过滤器,这将导致它在您的身份验证过滤器之前被调用(假设过滤器不是预匹配过滤器,在这种情况下您还应该使用@Priority
注释)。
这个过滤器的作用是检查请求是否是预检请求,如果是,它会用 200 中止整个请求,这会导致请求跳过资源方法,跳过它之后的所有其他请求过滤器, 并跳转到响应过滤器。在响应过滤器中,我们通过检查我们之前设置的属性来检查它是否是预检。如果是,那么我们设置 CORS 响应标头。如果您想了解有关 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 $http、CORS 和 Jersey 的基本身份验证的主要内容,如果未能解决你的问题,请参考以下文章
在 angularjs 中使用 $http.post() 时出现 CORS 问题
使用 python flask-restful 和消费 AngularJS(使用 $http)时出现 CORS(跨源...)错误
使用 CORS 的 Javascript 和 angularjs