使用AngularJS拦截器防止HTTP Basic Auth对话

时间:2014-06-09 22:53:34

标签: javascript ajax angularjs http authentication

我正在使用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调用(希望触发上面的拦截器),我看到了:

Authentication Required

如果我取消该对话框,我会看到“有一个401”的console.log输出,我希望看到而不是那个对话框

Got a 401

很明显,拦截器正在工作,但它的拦截太晚了!

我在网上看到很多关于在这种情况下使用AngularJS进行身份验证的帖子,他们似乎都使用HTTP拦截器,但没有一个提到弹出的基本身份验证对话框。我对其外表的一些错误想法包括:

  • 在回复中缺少Content-Type: application/json标题?不,它就在那里。
  • 除了承诺拒绝之外还需要退货吗?无论返回什么内容,该代码总是在对话后运行。

我是否错过了一些设置步骤或错误地使用拦截器?

3 个答案:

答案 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, */*"};