Как сохранить токен-маркер на предъявителя в браузере cookie с помощью функции AngularJS

Я создал токен на предъявителя, используя 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 :(");
  });
};

Поэтому я хочу сохранить этот токен в куки браузера. Если этот токен присутствует там, то возьмите токен и получите данные с сервера IIS. В противном случае перенаправьте на страницу входа, чтобы получить новый токен.

Точно так же, если пользователь нажимает кнопку выхода, он должен удалить токен из cookie браузера.

Как это сделать? Это возможно? Это правильный способ аутентификации и авторизации пользователя? Что делать, если есть токен нескольких пользователей?

Ответ 1

В API AngularJS имеется служба $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 > . И добавьте его в свое приложение angular: angular.module('myApp', ['ngCookies']);. Документы для 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'];

Ответ 2

Я бы посоветовал не хранить данные в cookie, в целях безопасности вы должны установить cookie для защиты и HttpOnly (недоступно из javascript). Если вы не используете SSL, я бы предложил перейти к https.

Я бы передал токен из конечной точки auth в ответ json:

{
    tokenData: 'token'
}

Вы можете сохранить данные токена в sessionStorage с помощью службы $window:

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

Он будет очищен после того, как пользователь закроет страницу, и вы можете вручную удалить ее, установив ее в пустую строку:

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

Edit:

Реализация перехватчика для захвата данных, адаптированная из 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'];