javascript 使用 AngularJS 拦截器阻止 HTTP 基本身份验证对话框
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24130308/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Preventing HTTP Basic Auth Dialog using AngularJS Interceptors
提问by Collin Allen
I'm building an AngularJS (1.2.16) web app with a RESTful API, and I'd like to send 401 Unauthorized responses for requests where authentication information is invalid or not present. When I do so, even with an HTTP interceptor present, I see the browser-presented basic "Authentication Required" dialog when an AJAX request is made via AngularJS. My interceptor runs afterthat dialog, which is too late to do something useful.
我正在构建一个带有 RESTful API 的 AngularJS (1.2.16) Web 应用程序,我想为身份验证信息无效或不存在的请求发送 401 未经授权的响应。当我这样做时,即使存在 HTTP 拦截器,当通过 AngularJS 发出 AJAX 请求时,我也会看到浏览器显示的基本“需要身份验证”对话框。我的拦截器在那个对话框之后运行,这已经太晚了,无法做一些有用的事情。
A concrete example:
一个具体的例子:
My backend API returns 401 for /api/things
unless an authorization token is present. Nice and simple.
/api/things
除非存在授权令牌,否则我的后端 API 将返回 401 。好看又简单。
On the AngularJS app side, I've looked at the docsand set up an interceptor like this in the config
block:
在 AngularJS 应用程序方面,我查看了文档并在config
块中设置了这样的拦截器:
$httpProvider.interceptors.push(['$q', function ($q) {
return {
'responseError': function (rejection) {
if (rejection.status === 401) {
console.log('Got a 401')
}
return $q.reject(rejection)
}
}
}])
When I load my app, remove the authentication token, and perform an AJAX call to /api/things
(to hopefully trigger the above interceptor), I see this:
当我加载我的应用程序,删除身份验证令牌,并执行 AJAX 调用/api/things
(希望触发上述拦截器)时,我看到:
If I cancel that dialog, I see the console.log
output of "Got a 401" that I was hoping to see instead of that dialog:
如果我取消那个对话框,我会看到console.log
我希望看到的“Got a 401”的输出而不是那个对话框:
Clearly, the interceptor is working, but it's intercepting too late!
显然,拦截器正在工作,但拦截太晚了!
I see numerous posts on the web regarding authentication with AngularJS in situations just like this, and they all seem to use HTTP interceptors, but none of them mention the basic auth dialog popping up. Some erroneous thoughts I had for its appearance included:
我在网上看到很多关于在这种情况下使用 AngularJS 进行身份验证的帖子,它们似乎都使用了 HTTP 拦截器,但没有一个提到弹出的基本身份验证对话框。我对其出现的一些错误想法包括:
- Missing
Content-Type: application/json
header on the response? Nope, it's there. - Need to return something other than promise rejection? That code always runs after the dialog, no matter what gets returned.
Content-Type: application/json
响应中缺少标头?不,它在那里。- 需要返回承诺拒绝以外的东西吗?无论返回什么,该代码始终在对话框之后运行。
Am I missing some setup step or using the interceptor incorrectly?
我是否遗漏了一些设置步骤或错误地使用了拦截器?
采纳答案by Collin Allen
Figured it out!
弄清楚了!
The trick was to send a WWW-Authenticate
response header of some value other than Basic
. You can then capture the 401 with a basic $http
interceptor, or something even more clever like angular-http-auth.
诀窍是发送一个WWW-Authenticate
除Basic
. 然后,您可以使用基本$http
拦截器或更聪明的东西(如angular-http-auth )捕获 401 。
回答by Busata
I had this issue together with Spring Boot Security (HTTP basic), and since Angular 1.3 you have to set $httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';
for the popup not to appear.
我和 Spring Boot Security (HTTP basic) 一起遇到了这个问题,从 Angular 1.3 开始,你必须设置$httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';
不出现弹出窗口。
回答by Alex Szabó
For future reference
备查
I've come up with this solution when trying to handle 401
errors.
I didn't have the option to rewrite Basic
to x-Basic
or anything similar, so I've decided to handle it on client side with Angular.
我在尝试处理401
错误时提出了这个解决方案。我没有改写选项Basic
来x-Basic
或类似的东西,所以我决定来处理它与角客户端。
When initiating a logout, first try making a bad request with a fake user to throw away the currently cached credentials.
启动注销时,首先尝试向假用户发出错误请求以丢弃当前缓存的凭据。
I have this function doing the requests (it's using jquery's $.ajax
with disabled asynch calls):
我有这个函数来处理请求(它使用$.ajax
带有禁用异步调用的jquery ):
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;
}
So when I try to log a user out, this happens:
因此,当我尝试注销用户时,会发生这种情况:
//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, */*"};