Количество внешних запросов при обслуживании ресурса

Итак, у меня есть веб-приложение, которое обрабатывает множество запросов на сервер для данных. Требование к проекту должно иметь очень быстрое время отклика сервера. Сервер размещен на платформе, основанной на облаке.

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

Текущий поток выглядит так:

  • Пользователь обращается к ресурсу
  • Попытка получить сеанс на основе идентификатора сеанса через кеш. Это запрос кэша.
  • Пользователь аутентифицируется через состояние сеанса (при входе в систему).
  • Запрос данных отправляется, как правило, через кеш.
  • Данные возвращаются пользователю.

Проблема с этим подходом заключается в том, что он дважды ударяет по кешу. Удаление сеанса в целом вызвало значительное улучшение скорости (около 50%).

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

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


Примечание: Я использую ASP.NET MVC/WebAPI с С#, но я не считаю это очень релевантным для вопроса, поэтому я не могу оставить язык и платформу из-за он.

Ответ 1

Вы хотели бы объединить шаги аутентификации и запроса ресурсов в один запрос. Это происходит не только быстрее, но и безопаснее, чем ваша реализация. Рассмотрим следующий сценарий:

  • Пользователь аутентифицируется на сервере. Результат - успех.
  • Идентификация изменена. (например, пользователь меняет пароль, администратор решает заблокировать учетную запись пользователя и т.д.).
  • Пользователь делает запрос с использованием sessionID в шаге 1.

Чтобы гарантировать, что пользователю не предоставлен доступ к ресурсу, вы должны аутентифицировать пользователя именно на шаге 3. Но это не имеет смысла, вы уже аутентифицировали этого пользователя ранее на шаге 1..

HTTP, в основном, предназначен именно для этого. Существуют различные способы передачи информации аутентификации вместе с запросом, например:

  • Введите информацию об аутентификации в контент (глупо, но работает)
  • Включить аутентификацию в URL-адрес, например. example.com/pic/123?sessionID=abc (лучше, но делает ваш URL уродливым и длинным)
  • Сохранять информацию о сеансе в файле cookie (лучше, но что, если клиент не поддерживает cookie?) Что означает истечение срока действия cookie?)
  • Аутентификация HTTP-заголовка (мои лучшие личные рекомендации)

У самого HTTP есть заголовок аутентификации, который должен быть совместим с "базовой аутентификацией" (он определенно определен, посмотрите, если вам интересно). Но вы можете реализовать свой собственный пользовательский заголовок.

Любой поиск в кэше должен быть медленным (по сравнению с вычислением), поэтому вы должны полностью исключить кеш для части аутентификации. Ваш сервер должен быть без гражданства; то есть не отслеживать сеансы входа в систему. Откуда вы знаете, действительно ли SessionID? Поместите на него временную метку. И чтобы другие не подделывали sessionID, подпишите его также.

Итак, ваш HTTP-запрос будет выглядеть примерно так (псевдокод):

var request = new HttpRequest();
request.url = "example.com/pic/123";
request.Headers["CustomAuth"] = "id=abc&t=123456789&s=01de45890a";

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

Теперь на вашем сервере сделайте что-то вроде этого:

public void Get(){
    var authHeader = Request.Headers["CustomAuth"];
    if(!validate(authHeader)){
        Response.StatusCode = 404;
        Response.End();
    }else{
        //something else
    }
}

Если вам нужно выполнить авторизацию login + session authenticate + resource request в одном запросе, тогда для проверки подлинности всего 2 способа. Пользователи могут либо указать комбинацию имени пользователя/пароля, либо ключ сеанса. Подумайте об этом сценарии, который исходит из API, над которым я работал:

  • пользовательский регистратор с именем пользователя/паролем Сервер
  • отвечает на успех/неудачу регистрации (например, имя пользователя уже выполнено)
  • Если это было успешно, теперь пользователь вступает в систему с именем пользователя/паролем combo
  • сервер возвращает токен сеанса

Не было бы проще (и быстрее), если мы сделаем так:

  • пользовательский регистратор с именем пользователя/паролем
  • Если это успех, ответьте "reg success" и "sessionToken = xxxxxx". если это ошибка, ответьте "reg failure".

Надеюсь, это даст вам некоторую идею.

Ответ 2

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