Подтвердить что ты не робот

Аутентификация для приложения Node.js с Angular.js и iOS клиентами

Я пытался прочитать как можно больше разных ответов и сообщений, но я все еще не могу полностью решить решение, которое соответствует моим потребностям. Я пытаюсь разработать лучший (наиболее эффективный, но в большей степени более безопасный) способ обработки аутентификации пользователя, входа в систему и т.д.

У меня есть сервер Node.js, работающий в Express; У меня есть веб-приложение Angular.js; и у меня есть приложение для iOS. Я открываю API RESTful с помощью Express/Node.js.

Cookies

Первое, что я прочитал, - это использовать куки файлы и хранить токен/идентификатор сеанса на стороне сервера (хешированный) и на стороне клиента (unhashed). Клиент будет передавать этот идентификатор с каждым запросом, сервер будет хешировать его, анализировать и обрабатывать запрос соответствующим образом. Это не означает, что RESTful (не большая проблема), но что более важно, мне пришлось бы дублировать мой API: один для аутентификации имени пользователя и пароля (например, выполненный через curl) и один для проверки подлинности на основе файлов cookie (например, моего веб-приложения)?

Еще одна проблема с этим: что бы я сделал, если бы у меня было несколько соединений от одного пользователя, например. они вошли в два браузера, iPhone и iPad. Будет ли мое хранилище идентификаторов сеансов теперь быть массивом?

HTTP Basic Auth

Следующей идеей было использование HTTP Basic Auth (с SSL), которое кажется достаточно простым, но не рекомендуется, потому что вам необходимо передать имя пользователя и пароль с каждым запросом. Если бы я должен был сделать это с помощью HTTP Basic Auth, я бы сохранил имя пользователя и пароль в файлах cookie (или локальном хранилище HTML), чтобы использовать функцию "Запомнить меня"? Или я мог бы объединить два: использовать HTTP Basic Auth для фактических запросов (опубликовать новое сообщение и т.д.) И просто использовать идентификатор сеанса, хранящийся в файле cookie, для первоначального входа в систему/запомнить меня аспекты?

Является ли передача идентификатора сеанса более безопасным, чем просто передача пароля пользователя? Как? Идентификатор сеанса будет действовать якобы как пароль, поэтому для меня передача будет иметь те же проблемы безопасности, что и передача пароля.

Базовый Auth, по-видимому, поддерживается на всех платформах, что идеально. Кажется, что основным недостатком является передача данных аутентификации клиента с каждым запросом. Есть ли способ смягчить эту проблему?

OAuth

OAuth кажется излишним для моих нужд. Я думаю, что потерял бы способность выполнять команды curl для тестирования моего API. Как OAuth улучшает метод cookie?

Как вы, вероятно, можете сказать, меня немного смущает разнообразная информация, поэтому, если у вас есть набор хороших ссылок, применимых к этому сценарию, я бы с удовольствием их прочитал. Я пытаюсь найти решение, которое подходит для всех платформ, но по-прежнему максимально безопасно. Кроме того, если у меня есть какая-либо из моих терминов неправильно, пожалуйста, исправьте меня, потому что это облегчит мне поиск.

Спасибо.

Update:

Я думал об этой проблеме, и у меня была идея. Скажите, пожалуйста, если это глупо/небезопасно/любая обратная связь, потому что я не уверен, что это хорошо.

Когда пользователь входит в систему, мы генерируем случайный идентификатор сеанса (соленый и т.д.). Этот необязательный идентификатор сеанса отправляется клиенту, который клиент может хранить (например, в файлах cookie), если они выбирают; идентификатор сеанса хранится в базе данных.

Этот идентификатор сеанса затем по желанию отправляется с каждым запросом как заголовок HTTP-аутентификации или строка запроса, либо клиент может просто отправить имя пользователя и пароль, если они захотят (что дает нам наш обычный REST API). На конце сервера мы сначала проверяем параметр идентификатора сеанса, если он отсутствует, мы проверяем имя пользователя/пароль. Если не существует ошибки.

На сервере мы проверяем, что идентификатор сеанса связан с правильным именем пользователя. Если это так, мы завершаем запрос.

Каждый раз, когда пользователь входит в систему, мы создаем новый идентификатор сеанса или удаляем текущий и отправляем его с ответом на запрос журнала.

Я думаю, что это позволяет мне использовать обычный REST API, где это уместно, с Basic Auth и поддерживать сеансы/запоминать мне функциональность. Он не решает проблему множественных журналов, но в остальном я думаю, что этот путь должен был бы. Пожалуйста, дайте мне знать.

4b9b3361

Ответ 1

Я бы использовал аутентификацию на основе токенов, где вы можете отправить токен (автоматически) с каждым запросом. Вам нужно будет войти в систему один раз, сервер предоставит вам токен, который вы можете использовать для отправки с каждым запросом. Этот токен будет добавлен в заголовок HTML, так что вам не нужно изменять каждый запрос в браузере.

Вы можете установить определенные вызовы в API, чтобы они всегда нуждались в токене, в то время как другие могут не быть защищенными токеном.

Для Express вы можете использовать express-jwt (https://www.npmjs.org/package/express-jwt)

var expressJwt = require('express-jwt');

// Protect the /api routes with JWT
app.use('/api', expressJwt({secret: secret}));

app.use(express.json());
app.use(express.urlencoded());

Если вы хотите выполнить аутентификацию, вы можете создать эту функцию на своем экспресс-сервере:

app.post('/authenticate', function (req, res) {
  //if is invalid, return 401
  if (!(req.body.username === 'john.doe' && req.body.password === 'foobar')) {
    res.send(401, 'Wrong user or password');
    return;
  }

  var profile = {
    first_name: 'John',
    last_name: 'Doe',
    email: '[email protected]',
    id: 123
  };

  // We are sending the profile inside the token
  var token = jwt.sign(profile, secret, { expiresInMinutes: 60*5 });

  res.json({ token: token });
});

И для защищенных вызовов что-то, что начинается с /api:

app.get('/api/restricted', function (req, res) {
  console.log('user ' + req.user.email + ' is calling /api/restricted');
  res.json({
    name: 'foo'
  });
});

В вашем приложении Angular вы можете войти с помощью:

$http
      .post('/authenticate', $scope.user)
      .success(function (data, status, headers, config) {
        $window.sessionStorage.token = data.token;
        $scope.message = 'Welcome';
      })
      .error(function (data, status, headers, config) {
        // Erase the token if the user fails to log in
        delete $window.sessionStorage.token;

        // Handle login errors here
        $scope.message = 'Error: Invalid user or password';
      });

И создав аутентификационный перехватчик, он автоматически отправит токен с каждым запросом:

myApp.factory('authInterceptor', function ($rootScope, $q, $window) {
  return {
    request: function (config) {
      config.headers = config.headers || {};
      if ($window.sessionStorage.token) {
        config.headers.Authorization = 'Bearer ' + $window.sessionStorage.token;
      }
      return config;
    },
    response: function (response) {
      if (response.status === 401) {
        // handle the case where the user is not authenticated
      }
      return response || $q.when(response);
    }
  };
});

myApp.config(function ($httpProvider) {
  $httpProvider.interceptors.push('authInterceptor');
});

Если вам нужно поддерживать старые браузеры, которые не поддерживают локальное хранилище. Вы можете поменять $window.sessionStorage на библиотеку, такую ​​как AmplifyJS (http://amplifyjs.com/). Например, Amplify использует любое местное хранилище. Это будет означать что-то вроде этого:

    if (data.status === 'OK') {
      //Save the data using Amplify.js
      localStorage.save('sessionToken', data.token);
      //This doesn't work on the file protocol or on some older browsers
      //$window.sessionStorage.token = data.token;
      $location.path('/pep');
    }
  }).error(function (error) {
    // Erase the token if the user fails to log in
    localStorage.save('sessionToken', null);
    // Handle login errors here
    $scope.message = 'Error: Invalid user or password';
  });

И authintercepter мы поменяем:

angular.module('myApp.authInterceptor', ['myApp.localStorage']).factory('authInterceptor', [
  '$rootScope',
  '$q',
  'localStorage',
  function ($rootScope, $q, localStorage) {
    return {
      request: function (config) {
        config.headers = config.headers || {};
        config.headers.Authorization = 'Bearer ' + localStorage.retrieve('sessionToken');
        return config;
      },
      response: function (response) {
        if (response.status === 401) {
        }
        return response || $q.when(response);
      }
    };
  }
]);

В этой статье вы можете найти все, кроме AmplifyJS:

http://blog.auth0.com/2014/01/07/angularjs-authentication-with-cookies-vs-token/

Ответ 2

Посмотрите на генератор йома для angular и node? Генератор-angular -полная стадия имеет очень приятную структуру для аутентификации пользователя с использованием паспорта.

Здесь вы можете увидеть пример:

код: https://github.com/DaftMonk/fullstack-demo

Результат: http://fullstack-demo.herokuapp.com/

Надеюсь, что это поможет!

Ответ 3

Я использую generator- angular -fullstack, службы /api не защищены, получите ваш _id из /api/users/me, logout и перейдите в /api/users/your _id_here, вы поймете, что /api не защищены.