AngularJS 版本 1.4.8 应用程序在用户的浏览器保持打开状态多年(在本例中为 16 小时(后将数据发送到后端 REST 身份验证服务时,其登录表单将数据发送到后端 REST 身份验证服务时收到未处理的403
错误。 经过更深入的分析,根本原因是客户端 AngularJS 应用程序具有过时的 XSRF-TOKEN
和JSESSIONID
cookie,这导致后端 Spring Security 拒绝对公共/login1
服务的请求,因为 Spring 认为该请求是跨站点请求伪造的。
如果用户关闭所有浏览器窗口,然后在再次发出请求之前重新打开新的浏览器窗口,则可以手动解决此问题。 但这不是可接受的用户体验。 我已经阅读了此链接中的 AngularJS 文档,我看到我可以添加一个errorCallback
函数,但是我应该如何具体重写该函数来处理403
错误?
以下是授权服务中的原始this.logForm()
方法,您可以看到它不处理403
错误:
this.logForm = function(isValid) {
if (isValid) {
var usercredentials = {type:"resultmessage", name: this.credentials.username, encpwd: this.credentials.password };
$http.post('/login1', usercredentials)
.then(
function(response, $cookies) {
if(response.data.content=='login1success'){// do some stuff
} else {// do other stuff
}
}
);
}
};
以下是我对 this.logForm()
方法的修订版的粗略尝试,尝试按照 AngularJS 文档中的示例处理403
错误:
this.logForm = function(isValid) {
if (isValid) {
var usercredentials = {type:"resultmessage", name: this.credentials.username, encpwd: this.credentials.password };
$http({ method: 'POST', url: '/login1', usercredentials })
.then(
function successCallback(response, $cookies) {
// this callback will be called asynchronously when the response is available
if(response.data.content=='login1success'){// do some stuff
} else {// do other stuff
}
},
function errorCallback(response, status) {// is status a valid parameter to place here to get the error code?
// called asynchronously if an error occurs or server returns response with an error status.
if(status == 403){
this.clearCookies();
// try to call this POST method again, but how? And how avoid infinite loop?
}
}
);
}
};
需要对上面的代码进行哪些具体更改来处理由于服务器感知的 XSRF-TOKEN 和 JSESSIONID 问题而导致的 403 错误? 在删除 cookie 不能解决 403 错误的情况下,如何在删除 cookie 后第二次调用该帖子而不会导致无限循环?
我也在研究全局的错误处理方法,但存在公共和安全后端 REST 服务的组合,需要单独处理,从而导致复杂性。 此登录表单是用户输入的第一个点,我想在查看全局方法之前单独处理它,这些方法将使用为回复此 OP 而开发的方法保留对登录表单的单独处理。
你可以重组你的http调用以自动重试,并在你的控制器中使用承诺(或其他什么(
var httpPostRetry = function(url, usercredentials) {
var promise = new Promise(function(resolve, reject) {
var retries = 0;
var postRetry = function(url, usercredentials) {
if (retries < 3) {
$http({ method: 'POST', url: '/login1', usercredentials })
.then(function(result) {
resolve(result);
}).catch(function(result) {
retries ++;
postRetry(url, usercredentials);
});
} else {
reject(result);
}
};
}.bind(this));
return promise;
}
然后你会打电话
httpPostRetry(bla, bla).then(function(result) {
// one of the 3 tries must of succeeded
}).catch(function(result) {
// tried 3 times and failed each time
});
要处理特定的 http 错误,您可以广播该特定错误并在特定控制器中处理这种情况。或者使用服务封装状态,并让代码的其他部分处理该错误的 UI 流。
$rootScope.$broadcast('unauthorized http error', { somedata: {} });
这有帮助吗?
看看 angular-http-auth 模块以及那里是如何完成的。我认为您想要使用的一个关键元素是 http 拦截器。
用于全局错误处理、身份验证或任何类型的请求的同步或异步预处理或响应的后处理,希望能够拦截请求在传递给服务器之前,在之前响应它们被移交给启动这些内容的应用程序代码请求。拦截器利用承诺 API 来实现这一点需要同步和异步预处理。
在使用拦截器之后,您可以查看angular-http-auth http缓冲区以及它们在那里处理被拒绝请求的方式。如果他们的拦截器收到一个responseError
,他们将config
对象(基本上存储有关您的请求的所有信息(添加到缓冲区中,然后他们可以随时操作该缓冲区中的元素。当您收到 403 时,您可以轻松地熟练地使用他们的代码来代表您操作配置的 xsrfHeaderName、xsrfCookieName 或参数。