AngularJS中的$http身份验证标头

42

我有一个Angular应用程序,它正在访问一个Node API。我们的后端开发人员已经在API上实现了基本身份验证,并且我需要在我的请求中发送认证标头。

我已经找到了:

$http.defaults.headers.common['Authorization'] = 'Basic ' + login + ':' + password);

我已经尝试过:

.config(['$http', function($http) {
       $http.defaults.headers.common['Authorization'] = 'Basic ' + login + ':' +    password);
}])

除了直接将其附加到请求中:

$http({method: 'GET', url: url, headers: {'Authorization': 'Basic auth'}})})

但是没有一种方法有效。怎么解决?


真的很奇怪...你的配置文件里没有其他东西吗?或者你是在代理后面之类的东西吗? - Thomas Pons
8个回答

33

您正在混淆使用情况;实例化服务($http)不能在配置阶段中使用,而提供程序则无法在运行块中工作。请参考模块文档

  • 配置块(Configuration blocks) - […] 只能注入提供程序和常量到配置块中。这是为了防止在完全配置服务之前意外实例化它们。
  • 运行块(Run blocks) - […] 只有实例和常量可以被注入到运行块中。这是为了防止在应用程序运行时进行进一步的系统配置。

因此,请使用以下任一方式:

app.run(['$http', function($http) {
    $http.defaults.headers.common['Authorization'] = /* ... */;
}]);
app.config(['$httpProvider', function($httpProvider) {
    $httpProvider.defaults.headers.common['Authorization'] = /* ... */;
}])

2
为什么我们不能在控制器级别编写$http.defaults.headers.common['Authorization'] = /* ... */; - Arepalli Praveenkumar
3
因为这是一个配置问题,而且你正在处理该服务的一个具体实例。 - pascalwhoop
1
@DannyBullis - 只是一种约定,据我所知。也许这种约定是为了方便而制定的;往往你会在某个地方将HTTP头作为常量,因此使用字符串来寻址键可以让你使用这些常量作为键引用,例如 $http.defaults.headers.common[HTTP_HEADER_KEY_AUTH] - Eliran Malka
3
谢谢@EliranMalka,非常清楚易懂。 - Danny Bullis
2
@natureminded 谢谢,是的我知道。我只是对样式方法感到好奇。使用方括号表示法允许使用任意属性值来定义要访问的属性,而点表示法仅针对特定的、非动态定义的属性。这种约定在JavaScript中比仅在此特定实例中使用要广泛得多,但我不确定在这里使用方括号的原因是否有其他特定的原因。我只需要澄清一下 :) 谢谢你们的帮助。 - Danny Bullis
显示剩余3条评论

14

我有一个服务工厂,其中有一个像这样的Angular请求拦截器:

var module =  angular.module('MyAuthServices', ['ngResource']);

module
    .factory('MyAuth', function () {
    return {
        accessTokenId: null
    };
})    
.config(function ($httpProvider) {
    $httpProvider.interceptors.push('MyAuthRequestInterceptor');
})

.factory('MyAuthRequestInterceptor', [ '$q', '$location', 'MyAuth',
    function ($q, $location, MyAuth) {
        return {
            'request': function (config) {


                if (sessionStorage.getItem('accessToken')) {

                    console.log("token["+window.localStorage.getItem('accessToken')+"], config.headers: ", config.headers);
                    config.headers.authorization = sessionStorage.getItem('accessToken');
                }
                return config || $q.when(config);
            }
            ,
            responseError: function(rejection) {

                console.log("Found responseError: ", rejection);
                if (rejection.status == 401) {

                    console.log("Access denied (error 401), please login again");
                    //$location.nextAfterLogin = $location.path();
                    $location.path('/init/login');
                }
                return $q.reject(rejection);
            }
        }
    }]);

然后在我的登录控制器中,我使用以下代码存储访问令牌:

sessionStorage.setItem('currentUserId', $scope.loginResult.user.id);
sessionStorage.setItem('accessToken', $scope.loginResult.id);
sessionStorage.setItem('user', JSON.stringify($scope.loginResult.user));
sessionStorage.setItem('userRoles', JSON.stringify($scope.loginResult.roles));

这样我可以在登录后的每个请求中分配头信息。这只是我的做法,完全可以接受批评,但它似乎非常有效。


13
你可以在控制器中使用它:
.controller('Controller Name', ['$http', function($http) {
   $http.defaults.headers.common['Authorization'] = 'Basic ' + login + ':' + password;
}]);

它可能会起作用,但不应该在控制器中完成。 - Louie Almeda
2
应该在配置阶段完成,但也需要在登录后完成,因此您可以在登录控制器中设置它。 - Sjoerd de Wit
对我的情况来说非常合理。如果您从不同的API获取数据,则希望将其配置在特定部分而不是整个Web应用程序上。+1 - Fransis Q
1
@LouieAlmeda 我认为你是对的。这不应该在控制器中完成。但Sjoerd也有一点道理。您应该能够在登录时设置它。这就是为什么我将此类内容和其他$http调用放在工厂中的原因。我认为这样可以将逻辑与控制器中应发生的事情以及像这样的实际内容分开。 - david.carm
@david.carm 然后将其设置在你的登录服务上,从控制器中调用。除非你没有这个服务,并且在控制器中完成所有操作。 - Louie Almeda

6
angularjs文档中,您可以看到设置标题的一些方法,但我认为这就是您正在搜索的内容。
$http({
    method: 'POST',
    url: '/theUrl',
    headers: {
        'Authorization': 'Bearer ' + 'token'
         //or
         //'Authorization': 'Basic ' + 'token'
    },
    data: someData
}).then(function successCallback(response) {
    $log.log("OK")
}, function errorCallback(response) {
    if(response.status = 401){ // If you have set 401
        $log.log("ohohoh")
    }
});

我在我的AngularJS客户端与ASP.NET 5服务器中使用了这个结构,并且它起作用。


没有理由仅为Ajax身份验证标头将JQuery添加到Angular项目中。 - tier1

4
$http文档中,可以看到你应该使用$httpProvider来设置默认的头部信息:
.config(['$httpProvider', function($httpProvider) {
    $httpProvider.defaults.headers.common['Authorization'] = 'Basic auth';
}]);

2

实际应用示例:我从@MrZime那里学到了这个技巧 - 感谢!并阅读https://docs.angularjs.org/api/ng/service/$http#setting-http-headers

截至2018年3月2日,最新的NGULARJS版本为v1.6.x

        var req = {
            method: 'POST',
            url: 'https://api.losant.com/applications/43fdsf5dfa5fcfe832ree/data/last-value-query',
            headers: {
                'Authorization': 'Bearer ' + 'adsadsdsdYXBpVG9rZW4iLCJzrdfiaWF0IjoxNdfsereOiJZ2V0c3RfdLmlvInfdfeweweFQI-dfdffwewdf34ee0',
                'Accept': 'application/json',
                'Content-Type': 'application/json'
            },
            data: {
                "deviceIds": [
                    "a6fdgdfd5dfqaadsdd5",
                    "azcxd7d0ghghghghd832"
                ],
                "attribute": "humidity"
            }
        }




        $http(req).then(function successCallback(response) {

            $log.log("OK!")
             returnedData = response.data

        }, function errorCallback(response) {

            if (response.status = 401) { // If you have set 401

                $log.log("BAD 401")

            }
            else {

                $log.log("broken at last")

            }
        });

将其添加到您的.js文件中,并在您的.html文件中包含此your.js文件,然后在Chrome的调试/F12控制台中查看,您应该会得到OK状态,"returnedData"就是最终想要的内容。享受这些数据吧!

1

在将用户:密码附加到“Basic”之前,请尝试对其进行base64编码,例如:

headers: {
  'Authorization': "Basic " + auth64EncodedUserColonPass
}

1
在你的 aap.run 方法中添加下面一行。
$http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w';

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接