Формирование JWT-токенов в приложении #
Документация #
- Пять простых шагов для понимания JSON Web Tokens (JWT)
- Introduction to JSON Web Tokens
- java-jwt A Java Implementation of JWT
- java-awt JavaDoc
Подключение библиотеки Java JWT #
Библиотеку Java JWT можно использовать в любом JVM-проекте. Для веб-приложения необходимо добавить зависимость от библиотеки java-jwt
в build.gradle
. Возьмите последнюю доступную версию библиотеки. Выпуски можно посмотреть на mvnrepository.
Выбор алгоритма для подписи JWT-токена #
Библиотека поддерживает 3 варианта выполнения подписи:
- HMAC — вычисление подписи на основании секретного ключа.
- RSA — вычисление подписи с помощью асинхронного хеширования RSA.
- ECDSA — вычисление подписи с помощью асинхронного хеширования ECDSA. Отличается от RSA более коротким ключом и более высокой стойкостью.
Использование RSA и ECDSA требует от разработчика создание валидной пары ключей. Желательно, чтобы сами ключи были выданы соответствующим сертифицированным центром. Обычно применяется, если служба идентификации отделена от самого приложения.
В рамках лабораторной и закрытых установок достаточно использовать HMAC-подписи. Секретный ключ для HMAC следует размещать в настройках приложения, чтобы его можно было подменить.
Указание алгоритма #
Для описания конкретного алгоритма подписи используется класс Algorithm. Для выбора алгоритма достаточно вызвать соответствующий метод алгоритма для подписи токена и передать ему необходимые данные.
Для создания алгоритма HMAC 512 следует воспользоваться методом Algorithm.HMAC512. Ему в качестве аргумента необходимо передать секретный ключ.
Описание алгоритма с параметрами настроек остаются актуальными во время работы всего приложения. Объект алгоритма можно создать один раз, а затем использовать при создании и проверки всех токенов в приложении.
Формирование JWT-токена #
Для создания подписи необходимо воспользоваться классом JWTCreator.Builder, который реализует шаблон проектирования строитель. Он предоставляет ряд методов, каждый из которых, позволяет установить поля для формируемого JWT-токена. Когда все поля установлены можно сформировать токен, вызвав метод sign. Данный метод возьмёт все данные, переданные ранее строителю, сформирует JWT-токен и подпишет его. Закодированный в base64-токен будет возвращён в виде строки.
В JWT-токен можно поместить любые данные, однако рекомендуется указать следующие поля:
- withSubject() — для указания идентификатора пользователя. Затем это поле можно будет использовать для идентификации пользователя.
- withExpiresAt() — для указания времени истечения времени работы токена, чтобы они не были бесконечно долгими. Есть 2 версии данного метода, принимающие разные формы указания конкретного момента истечения работы токена.
- withIssuer() — для указания названия организации, которая выдала данный JWT-токен.
Стоит учесть, что метод sign может выбросить исключение. Его необходимо обработать в приложении.
Ввиду того, что при формировании JWT-токена все данные зависят от контекста вызова, то объект класса JWTCreator.Builder необходимо создавать заново для каждого запроса на создание токена.
Проверка JWT-токена #
Для проверки JWT-токена необходимо воспользоваться классом JWTVerifier. Для создания такого объекта нужно воспользоваться методом JWT.require, который принимает в качестве аргумента алгоритм для проверки подписи и возвращает объект типа Verification. Последний тоже реализует шаблон проектирования строитель. С помощью его методов можно описать ограничения: является ли проверяемый токен корректным или нет. После указания всех свойств необходимо вызвать метод build(), который вернёт объект типа JWTVerifier.
Для проверки указанных свойств можно воспользоваться методами:
- withIssuer() — добавить проверку на идентификацию организации, выдавшей данный токен.
- acceptExpiresAt() — для указания промежутка времени, в течение которого выданный токен считается корректным. Т.е. позволяет продлить время жизни токена на указанное время.
В отличие от задачи формирования JWT-токена созданный объект JWTVerifier можно повторно использовать для проверки JWT-токенов. Объект данного класса можно создать один раз для работы всего приложения, как и объект класса Algorithm.
Для проверки конкретного токена необходимо использовать метод JWTVerifier.verify(). Данный метод принимает себе в качестве аргумента JWT-токен и возвращает декодированный токен. В случае, если условия проверки не верны, тогда метод выбросит одно из следующих исключений:
- AlgorithmMismatchException — алгоритм подписи не совпал.
- SignatureVerificationException — подпись токена не верна.
- TokenExpiredException — время жизни токена истекло.
- MissingClaimException — в переданном токене нет нужного разрешения.
- IncorrectClaimException — в переданном токене значение разрешения не совпало с исходным
- JWTVerificationException — базовый класс для всех типов исключений.
Если исключение не было выброшено, то содержимое JWT-токена можно прочитать из содержимого структуры DecodedJWT. Для аутентификации пользователей нас будет интересовать метод getSubject().
Задача. Реализуйте процедур создания JWT-токенов #
Реализуйте класс JwtTools, предоставляющий методы по созданию и проверке JWT-токенов.
- Добавьте в приложение зависимость от библиотеки Java JWT.
- Добавьте в настройки приложения возможность считывания соли для вычисления хеша подписи JWT-токена.
- Добавьте в приложение класс
JwtTools
, позволяющий выполнять операции по формированию и проверки JWT-токена. В конструктор объекта следует передать:- секретную строку для формирования алгоритма
- название организации для указания внутри токена
- указание продолжительности жизни токена по умолчанию
- Добавьте в класс метод по созданию JWT-токена, который будет принимать в качестве аргумента идентификатор пользователя, строку. Данный метод должен возвращать строку, содержащую JWT-токен.
- Добавьте в класс метод по проверке JWT-токена. Данный метод должен принимать в качестве аргумента строку-токен и возвращать идентификатор пользователя, закодированный внутри токена.
- Проверьте работоспособность данных методов. Либо путём написания модульных тестов, либо путём вызова данных методов в главном файле приложения.