Как создать токен аутентификации с помощью Java
На моем Java EE6, сервисе REST, я хочу использовать токены аутентификации для входа с мобильных устройств. Пользователь отправит свое имя пользователя, пароль, а сервер отправит обратно токен, который будет использоваться для авторизации пользователя на его дальнейшие запросы для данного время.
Могу ли я просто создать токен сам, как это?(Я думаю, мне не нужно шифровать это, так как я буду использовать HTTPS.)
String token = UUID.randomUUID().toString().toUpperCase()
+ "|" + "userid" + "|"
+ cal.getTimeInMillis();
Или есть более стандартный способ создания моих токенов? может быть, он существует в одном из API
5 ответов
Эффективная схема, которую вы предлагаете, предоставляет клиенту неограниченный доступ к вашим услугам. После первоначального входа в систему клиенту будут доступны UID и "идентификатор пользователя", которые можно просто объединить с всегда действительной отметкой времени.
Если вам нужен сервис с "логином" и токеном сеанса, то почему бы просто не использовать HttpSession?
Для Java 8 и выше самым быстрым и простым решением было бы:
private static final SecureRandom secureRandom = new SecureRandom(); //threadsafe
private static final Base64.Encoder base64Encoder = Base64.getUrlEncoder(); //threadsafe
public static String generateNewToken() {
byte[] randomBytes = new byte[24];
secureRandom.nextBytes(randomBytes);
return base64Encoder.encodeToString(randomBytes);
}
Пример вывода:
wrYl_zl_8dLXaZul7GcfpqmDqr7jEnli
7or_zct_ETxJnOa4ddaEzftNXbuvNSB-
CkZss7TdsTVHRHfqBMq_HqQUxBGCTgWj
8loHzi27gJTO1xTqTd9SkJGYP8rYlNQn
Приведенный выше код будет генерировать случайную строку в кодировке base64 с 32 символами. В кодировке Base64 каждый символ кодирует 6 бит данных. Итак, для 24 байтов из приведенного выше примера вы получите 32 символа. Вы можете изменить длину выходной строки, изменив количество случайных байтов. Это решение более безопасно, чемUUID
(который использует только 16 случайных байтов) и генерирует строку, которую можно безопасно использовать в URL-адресах HTTP.
Чтобы создать трудно угадываемый токен в Java java.security.SecureRandom
Например
SecureRandom random = new SecureRandom();
byte bytes[] = new byte[20];
random.nextBytes(bytes);
String token = bytes.toString();
Вместо того, чтобы включать имя пользователя в токен, было бы лучше кэшировать пользователя: карта токена в памяти или в базе данных.
Создание уникального токена полностью основано на логике и количестве используемых вами параметров. Supplier
Функциональный интерфейс Java 8 поможет вам:
Supplier<String> tokenSupplier = () -> {
StringBuilder token = new StringBuilder();
long currentTimeInMilisecond = Instant.now().toEpochMilli();
return token.append(currentTimeInMilisecond).append("-")
.append(UUID.randomUUID().toString()).toString();
};
System.out.println(tokenSupplier.get());
Выход:
1591457374665-d5eff25f-b083-41c3-a90d-a89adcc45043
Вы можете узнать больше об этом здесь - Java Token
Существует способ создания токенов, который не может быть скомпрометирован, но может также использоваться для аутентификации.
Создайте токен, который будет объединен:
base64 (имя пользователя + срок действия + другие значения для клиента + закодированные 3des (имя пользователя, срок действия, исходный IP-адрес, идентификатор браузера, другие значения для клиента))
Клиент может использовать токен для аутентификации запроса, например, использование веб-токена JSON (RFC 7515).
На стороне сервера ключи, которые используются для кодирования 3des, могут вращаться со временем, как токен. Каждый запрос содержит токен для аутентификации, и каждый ответ содержит один и тот же токен или новый до истечения срока действия.
В этом случае токен содержит имя пользователя, поэтому при проверке подлинности по запросу необходимо только проверить, является ли кодированная часть 3des действительной или нет (так же, как и источник запроса ip такой же. В этом случае, если кто-то украл токен, удобство использования токена более ограничено идентификатором сеанса. Вы можете составить другие идентификаторы для токена, например, браузер и т. д. Сложнее подделать запрос, потому что злоумышленник должен подделать больше вещей - что ему неизвестно, потому что он не знает, что находится в закодированной части токен. (На самом деле нет идеальной безопасности, только может усложнить взлом)
Плюсы этого решения:
- Каждая часть является стандартной, но не все вместе, и злоумышленник должен знать детали реализации, чтобы иметь возможность атаковать.
- Клиентская сторона может использовать части токена для отображения информации из токена, в то время как сам токен защищен, потому что каждая незашифрованная часть содержится в зашифрованной части - поэтому не может быть изменена без аннулирования токена на стороне сервера - поэтому его легко обнаружить атака.
- Для кластеризации нет необходимости репликации сессий / липких сессий. Ключей 3des достаточно для репликации между узлами, поэтому он подходит для серверной стратегии без сохранения состояния.
Минусы
Сложнее реализовать на стороне сервера, поскольку для этого решения необходимо реализовать алгоритм генерации / проверки токенов на стороне сервера. Для этого рекомендуется использовать фильтр сервера.
Клиенты должны реализовать хранилище токенов - вместо того, чтобы рекомендовать хранилище сессий браузера cookie - проще украсть куки.
- Необходимо убедиться, что ключи 3des достаточно защищены - рекомендуется использовать безопасность Java, чтобы избежать компромисса.
public class SecureTokenGenerator {
public static final String CHARACTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
// 2048 bit keys should be secure until 2030 - https://web.archive.org/web/20170417095741/https://www.emc.com/emc-plus/rsa-labs/historical/twirl-and-rsa-key-size.htm
public static final int SECURE_TOKEN_LENGTH = 256;
private static final SecureRandom random = new SecureRandom();
private static final char[] symbols = CHARACTERS.toCharArray();
private static final char[] buf = new char[SECURE_TOKEN_LENGTH];
/**
* Generate the next secure random token in the series.
*/
public static String nextToken() {
for (int idx = 0; idx < buf.length; ++idx)
buf[idx] = symbols[random.nextInt(symbols.length)];
return new String(buf);
}
}
Взято и значительно сжато с /questions/18192564/kak-sgenerirovat-sluchajnuyu-bukvenno-tsifrovuyu-stroku/18192568#18192568
REST основан на HTTP и рекомендует использовать базовый протокол, а не изобретать велосипед. HTTP использует куки для поддержки взаимодействий с состоянием, таких как запоминание аутентификации, а также поддерживает аутентификацию по имени пользователя и паролю.
Кроме того, Java EE поддерживает все это из коробки. Проверьте учебник