我正在使用RESTful API构建一个AngularJS(1.2.16)Web应用程序,并且我希望针对身份验证信息无效或不存在的请求发送401 Unauthorized响应。当我这样做时,即使存在HTTP拦截器,当通过AngularJS发出AJAX请求时,我会看到浏览器呈现的基本“Authentication Required”对话框。我的拦截器在该对话框之后运行,这对于做一些有用的事情已经太迟了。
具体示例:
我的后端API为/api/things
返回401,除非存在授权令牌。好又简单。
在AngularJS应用程序方面,我查看了docs并在config
块中设置了这样的拦截器:
$httpProvider.interceptors.push(['$q', function ($q) {
return {
'responseError': function (rejection) {
if (rejection.status === 401) {
console.log('Got a 401')
}
return $q.reject(rejection)
}
}
}])
当我加载我的应用程序时,删除身份验证令牌,并执行对/api/things
的AJAX调用(希望触发上面的拦截器),我看到了:
如果我取消该对话框,我会看到“有一个401”的console.log
输出,我希望看到而不是那个对话框:
很明显,拦截器正在工作,但它的拦截太晚了!
我在网上看到很多关于在这种情况下使用AngularJS进行身份验证的帖子,他们似乎都使用HTTP拦截器,但没有一个提到弹出的基本身份验证对话框。我对其外表的一些错误想法包括:
Content-Type: application/json
标题?不,它就在那里。我是否错过了一些设置步骤或错误地使用拦截器?
答案 0 :(得分:12)
想出来了!
诀窍是发送除WWW-Authenticate
以外的某个值的Basic
响应标头。然后,您可以使用基本的$http
拦截器捕获401,或者像angular-http-auth更加聪明的东西。
答案 1 :(得分:8)
我将此问题与Spring Boot Security(HTTP基本版)一起使用,因为Angular 1.3必须设置$httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';
才能使弹出窗口不显示。
答案 2 :(得分:1)
供将来参考
我在尝试处理401
错误时想出了这个解决方案。
我没有选择将Basic
重写为x-Basic
或类似内容,所以我决定在客户端使用Angular处理它。
启动注销时,首先尝试向假用户发出错误请求,以丢弃当前缓存的凭据。
我有这个功能来处理请求(它使用jquery' s $.ajax
和禁用的异步调用):
function authenticateUser(username, hash) {
var result = false;
var encoded = btoa(username + ':' + hash);
$.ajax({
type: "POST",
beforeSend: function (request) {
request.setRequestHeader("Authorization", 'Basic ' + encoded);
},
url: "user/current",
statusCode: {
401: function () {
result = false;
},
200: function (response) {
result = response;
}
},
async: false
});
return result;
}
因此,当我尝试将用户注销时,会发生这种情况:
//This will send a request with a non-existant user.
//The purpose is to overwrite the cached data with something else
accountServices.authenticateUser('logout','logout');
//Since setting headers.common.Authorization = '' will still send some
//kind of auth data, I've redefined the headers.common object to get
//rid of the Authorization property
$http.defaults.headers.common = {Accept: "application/json, text/plain, */*"};