Рекомендации по управлению токеном аутентификации
Я пишу клиент REST в Java с использованием HttpCLient, API REST, к которому я обращаюсь, требует токена аутентификации для каждого действия REST. Этот токен действителен в течение 24 часов.
То, как я сейчас обрабатываю это, вызывает метод "getAuth()
" каждый раз, когда мне нужно сделать вызов REST, который кажется накладным на сервере auth.
Как я могу удобно хранить этот токен и управлять его жизненным циклом?
Существуют ли какие-либо задокументированные рекомендации?
Я подумал о следующем решении
public class MySession {
String user;
String pass;
public MySession(String user, String pass) {
this.user = user;
this.pass = pass;
}
public getAuth() {
//user user, pass to get auth token
}
}
а затем передать объект сеанса любому классу, который содержит токен. Если токен истек, просто вызовите этот метод еще раз
Ответы
Ответ 1
Я предлагаю вам использовать следующий сценарий:
1) Сначала вызовите auth(username, password)
rest api, чтобы получить токен auth.
Если данные учетные данные в порядке, то просто отправьте файл cookie auth клиенту с кодом ответа HTTP 200.
2) Затем вы можете вызвать protected rest apis. Вам необходимо каждый раз отправлять auth cookie с вашим запросом.
3) Сервлет-фильтр (или что-то подобное) проверяет каждый входящий запрос и проверяет токен. Если токен действителен, запрос переходит к следующему методу, если вам не нужно генерировать ответ http 401/403.
Я предлагаю вам не писать собственный уровень аутентификации. Вместо установки и использования существующего. Я предлагаю вам OpenAM. Это превосходная система управления доступом с открытым исходным кодом.
Я также предлагаю вам не открывать сеанс на стороне сервера для целей аутентификации. Если у вас 10 клиентов, то 10 сеансов должны управляться сервером. Это не большая проблема. Но если у вас есть 100 или 1000 или миллионы разных клиентов, чем вам нужно больше памяти для хранения сеансов на сервере.
Ответ 2
Я предполагаю, что вы используете OAuth для авторизации. Если вы используете JWT или другие токены, это не имеет отношения к этой ситуации.
При выполнении авторизации вы получите access_token
с истечением срока действия и в зависимости от типа гранта, который вы запрашиваете (учетные данные клиента, код авторизации, неявный, владелец ресурса), refresh_token
.
Клиент должен хранить access_token
и истечение срока действия. Обновление refresh_token, если оно выпущено, должно храниться в секрете (остерегайтесь использовать правильный грант для вашего случая использования).
В последующих вызовах ваш клиент не должен запрашивать новые токены для каждого вызова, он должен использовать сохраненный access_token
.
Как только API начнет возвращаться 401 Unauthorized
, срок действия access_token
, вероятно, истек. Ваш клиент должен попытаться обновить access_token
с помощью refresh_token
, если у вас есть.
Если у вас нет refresh_token
или запрос обновления также не удался, поскольку refresh_token
больше недействителен, вы можете выполнить новый поток авторизации.
Вы можете использовать время истечения срока действия, чтобы узнать, когда получить новый access_token
либо через обновление, либо через новый полный поток авторизации. Это позволит избежать 401 Unauthorized
. В любом случае у вашего клиента должна быть политика возврата, когда этот ответ получен после использования действительного access_token
для некоторых вызовов.
Ответ 3
Если вас беспокоит слишком много обращений к базе данных, я предполагаю, что существует много веб-активности.
Я бы не рекомендовал использовать Session в вашем случае, а скорее хранить токен в cookie на клиенте.
В среде с высоким трафиком (который я предполагаю, что у вас есть) использование сеанса может потреблять много памяти сервера, а масштабируемость также может быть связана с необходимостью синхронизации сеансов внутри кластера.
Как упоминал также @Cássio Mazzochi Molin, вы можете использовать кеш в памяти для хранения данных и токенов, специфичных для пользователя. Это уменьшит количество обращений к базе данных, а также позволит вам масштабировать приложение при необходимости.
Ответ 4
Стандарт de facto не реализует ваше собственное решение (основное правило в безопасности: не реализует ваши собственные вещи!), но используйте де-факто стандартное решение, а именно JSON Web Tokens.
Документация на сайте, но основная идея заключается в том, что вам нужно сохранить только одно значение (секретный ключ сервера), а затем вы можете проверить все претензии, выпущенные первоначально сервером (который в вашем случае содержит время истечения срока действия).
Ответ 5
Для краткости я предполагаю, что вы вызываете конечную точку, которую вы не можете изменить. Как вы должны реализовать, будет сильно зависеть от того, является ли токен приложением или пользователем (один токен для всех пользователей в экземпляре общего приложения или один токен на пользователя).
Если это один токен для всего приложения:
- Храните его в памяти вместе с временной меткой времени (или, как альтернатива, уловите ошибку с истекшим сроком действия, запросите новый токен и повторите первоначальный запрос), обновите его, если он не существует/истек.
- Если вы беспокоитесь о повторном запросе маркеров API после перезапуска приложения, также сохраните его в базе данных и загрузите при запуске, если он существует
Если это один токен для пользователя:
- Храните его в своем пользовательском сеансе, именно для того, для каких сеансов используются, если вы используете пользователей, то у них будет сеанс, а накладные расходы уже есть.
- Если вы не хотите повторно запрашивать токен каждый раз, когда они регистрируют свой текущий токен в БД и загружают его в свой сеанс при входе в систему
Ответ 6
Вы можете создать менеджер и сохранить auth-cookie во время входа в поток локально, как показано ниже. Вы можете получить файл cookie с getAuth()
до тех пор, пока он не будет проживать.
public class Manager {
private static final ThreadLocal<String> SECURITY_CONTEXT = new ThreadLocal<>();
public static void setAuth(String auth) {
SECURITY_CONTEXT.set(auth);
}
public static String getAuth() {
return SECURITY_CONTEXT.get();
}
public static void clear(){
SECURITY_CONTEXT.remove();
}
}
Ответ 7
Вы должны использовать JsonWebToken (кратко JWT) для такого рода вещей. JWT имеет поддержку для установки даты истечения срока действия. Существует множество библиотек для использования этого метода, и вы можете читать здесь
Существуют версии java-версий currenlty и все они могут проверить, действительно ли токен (проверка проверки)
![введите описание изображения здесь]()
Ответ 8
Итак, если я правильно понимаю, вы используете один и тот же токен для всех своих запросов (это означает, что пока ваше приложение работает и вы обновляете токены, вы должны быть в порядке. Я буквально имел ту же проблему и вот как я это разрешил. У меня есть одноэлементный класс, который инициализируется в начале приложения за один раз и обновляет токен, когда он недействителен. Я использую С#, Asp.NET MVC5 и AutoFac для DI, но я Конечно, вы можете сделать то же самое с Java и Spring.
Обновление свойства одноэлемента с безопасностью потока
Ответ 9
Использовать токены json для обмена информацией между двумя клиентами. Токен будет действовать только в течение 24 часов, после этого все последующие вызовы в заголовке будут отклонены.
Ответ 10
- Auth Token для каждого запроса является правильным подходом, рассмотрите масштабирование сервера auth для проблемы с производительностью.
- При первой успешной аутентификации (имя пользователя и пароль) создайте приватную партию ключей. Храните закрытый ключ как токен безопасности сеанса (SST) и отправьте открытому ключу как Клиентский ключ общественной безопасности (PSCK) для клиента
- Во всех запросах, кроме входа (аутентификации), клиент отправляет PSCK для защиты кражи имени пользователя и пароля, а сервер может проверять PSCK на срок до истечения регулярного промежутка времени, экономя время обработки.
- Если система имеет проблемы с производительностью на стороне аутентификации, настройте отдельный сервер auth с масштабируемостью.
- Нет маркера или пароля для кэширования, обмена незашифрованных и отправки внешней зоны безопасности. Не публикуйте параметры URL.