如何使用AngularJS将身份验证承载令牌存储在浏览器cookie中

Posted

技术标签:

【中文标题】如何使用AngularJS将身份验证承载令牌存储在浏览器cookie中【英文标题】:How to store authentication bearer token in browser cookie using AngularJS 【发布时间】:2016-04-05 09:26:10 【问题描述】:

我使用 ASP.net Identity 创建了一个不记名令牌。在 AngularJS 中,我编写了这个函数来获取授权数据。

$scope.GetAuthorizeData = function () 
  $http(
    method: 'GET',
    url: "/api/Values",
    headers:  'authorization': 'bearer <myTokenId>' ,
  ).success(function (data) 
    alert("Authorized :D");
    $scope.values = data;
  ).error(function () 
    alert("Failed :(");
  );
;

所以我想将此令牌存储到浏览器 cookie 中。如果此令牌存在,则获取令牌并从 IIS 服务器获取数据,否则重定向到登录页面以登录以获取新令牌。

同样,如果用户点击退出按钮,它应该从浏览器 cookie 中删除令牌。

如何做到这一点?有可能吗?对用户进行身份验证和授权是否正确?如果有多个用户令牌怎么办?

【问题讨论】:

【参考方案1】:

我建议不要将数据保存在 cookie 中,出于安全考虑,您应该将 cookie 设置为安全和 HttpOnly(无法从 javascript 访问)。如果您不使用 SSL,我建议您转到 https

我会在 json 响应中从身份验证端点传递令牌:


    tokenData: 'token'

您可以使用$window 服务将令牌数据保存在sessionStorage 中:

$window.sessionStorage.setItem('userInfo-token', 'tokenData');

一旦用户关闭页面就会被清除,您可以通过将其设置为空字符串手动将其删除:

$window.sessionStorage.setItem('userInfo-token', '');

编辑:

用于捕获数据的拦截器实现,改编自 cbass(未测试,您可以检查响应/请求的对象以摆弄信息):

//Create a http interceptor factory
function accessTokenHttpInterceptor($window) 
    return 
        //For each request the interceptor will set the bearer token header.
        request: function($config) 
            //Fetch token from cookie
            var token=$window.sessionStorage.getItem('userInfo-token');

            //set authorization header
            $config.headers['Authorization'] = 'Bearer '+token;
            return $config;
        ,
        response: function(response) 
            //if you get a token back in your response you can use 
            //the response interceptor to update the token in the 
            //stored in the cookie
            if (response.config.url === 'api/token' && response.config.data.tokenData) 
                  //fetch token
                  var token=response.config.data.tokenData;

                  //set token
                  $window.sessionStorage.setItem('userInfo-token', token);
            
            return response;
        
    ;


accessTokenHttpInterceptor.$inject=['$window'];

【讨论】:

非常感谢。我还没有在 Angular JS 中尝试过 $window。也不知道使用 SSL。我应该在哪里写这些代码?能不能给我更明确的答案。 您可以将会话存储的处理程序放在服务中,或者像下面提到的 cbass 使用 httpInterceptor。 将令牌保存在会话存储中也意味着如果我在新选项卡中打开链接,则会话存储中的令牌不可用。用户需要再次进行身份验证(在每个选项卡上),这真的很烦人。可能的解决方案:***.com/a/32766809/1878249 @goflo 正确,具体取决于新选项卡的打开方式(它必须是新的浏览上下文,因此不共享 sessionStorage)。 localStorage 的回退对于这种情况很有用。使用window.name 保留数据的另一种选择,我发现这是一种有问题的技术,并会考虑作为最后的手段。话虽如此,在我的应用程序中打开新标签时我没有遇到任何问题。但我的配置可能与上面描述的略有不同(自从我接触该代码以来已经超过六个月了)。【参考方案2】:

AngularJS API 中有一个$cookies 服务可用,使用 ngCookies 模块。它可以像下面这样使用:

function controller($cookies) 
    //set cookie
    $cookies.put('token', 'myBearerToken');

    //get cookie
    var token=$cookies.get('token');

    //remove token
    $cookies.remove('token');

controller.$inject=['$cookies'];

你的情况是:

//inject $cookies into controller
$scope.GetAuthorizeData = function () 
    $http(
        method: 'GET',
        url: "/api/Values",
        headers:  'authorization': 'bearer <myTokenId>' ,
    )
    .success(function (data) 
        $cookies.put('token', data);
    ).error(function () 
        alert("Failed :(");
    );
;

您还必须添加angular-cookies module 代码。并将其添加到您的 Angular 应用程序中:angular.module('myApp', ['ngCookies']);。 Docs for Angular Cookies.

我还想建议使用Http interceptor,它将为每个请求设置不记名标头,而不必为每个请求自己手动设置。

//Create a http interceptor factory
function accessTokenHttpInterceptor($cookies) 
    return 
        //For each request the interceptor will set the bearer token header.
        request: function($config) 
            //Fetch token from cookie
            var token=$cookies.get['token'];

            //set authorization header
            $config.headers['Authorization'] = 'Bearer '+token;
            return $config;
        ,
        response: function(response) 
            //if you get a token back in your response you can use 
            //the response interceptor to update the token in the 
            //stored in the cookie
            if (response.config.headers.yourTokenProperty) 
                  //fetch token
                  var token=response.config.headers.yourTokenProperty;

                  //set token
                  $cookies.put('token', token);
            
            return response;
        
    ;

accessTokenHttpInterceptor.$inject=['$cookies'];

//Register the http interceptor to angular config.
function httpInterceptorRegistry($httpProvider) 
    $httpProvider.interceptors.push('accessTokenHttpInterceptor');

httpInterceptorRegistry.$inject=['$httpProvider'];

//Assign to module
angular
    .module('myApp')
    .config(httpInterceptorRegistry)
    .factory('accessTokenHttpInterceptor', accessTokenHttpInterceptor)

有了http interceptor,您就不需要为每个请求设置Authorization header

function service($http) 
    this.fetchToken=function() 
        //Authorization header will be set before sending request.
        return $http
            .get("/api/some/endpoint")
            .success(function(data) 
                 console.log(data);
                 return data;
            )
    

service.$inject=['$http']

正如鲍里斯所说:还有其他方法可以解决这个问题。您还可以使用localStorage 来存储令牌。这也可以与 http 拦截器一起使用。只需将实现从 cookie 更改为 localStorage。

function controller($window) 
    //set token
    $window.localStorage['jwt']="myToken";

    //get token
    var token=$window.localStorage['jwt'];

controller.$inject=['$window'];

【讨论】:

是的,知道了。谢谢你。很好的解释。 您好,&lt;myTokenId&gt; 在哪里?在哪里可以找到它?

以上是关于如何使用AngularJS将身份验证承载令牌存储在浏览器cookie中的主要内容,如果未能解决你的问题,请参考以下文章

通过查询字符串传递“承载”时,SignalR 身份验证失败

Web Api 2 Preflight CORS 请求承载令牌

在web api身份验证之后将令牌存储在浏览器本地存储中是否安全

Windows Azure Active Directory 承载身份验证

Autodesk API Forge身份验证承载

Auth0 - 在 Owin 上使用带有承载访问令牌的 JWT 使用 RS256 进行身份验证