Альтернатива Spring Security с использованием JJWT токена и Cookie, HttpServletRequest, HttpServletResponse
Коротко о главном. Конфигурации не нужны. На каждую страницу создаётся отдельный класс фильтр с методом аутентификации. Если к группе страниц доступ получает пользователь с одной и той же ролью, то используется один и тот же класс фильтр. Логично
Но страница авторизации устроена хитрее. Там аж 4 метода: авторизация если cookie полностью отсутствуют, аутентификация, обычная авторизация и получение изменённого cookie. Соответственно 1 и 3 методы похожи но на 1 стоит проверка cookie на null. В случае если 1 метод не отработал вызывается 2 и 3 соответственно. Можно было сделать 1 метод, но так он визуально более понятен.
Два последних метода были созданы из за невозможности возврата строки названия html страницы в стиле шаблонизатора Thymeleaf c изменённым куки. Ещё HttpServletResponse применим только внутри контроллера, поэтому в классах фильтрах только проверка Http запроса к серверу. Пример:
Переделал статью и дополнил в фильтр авторизации 2 последних метода из кода выше. Без последнего был баг. Он заключался с тем, что когда мы выходим из аккаунта и вводим рандомные данные, то аутентификация берётся из последнего сохранённого куки. Поэтому этот метод вызывается для очистки. Код взят с моего проекта. Тут задействован ещё и Spring Data
!!! Предполагается что вы знаете уже хоть какую-то ORM. Но напишите, если нужно дополнить статью этим фреймворком !!!
Первый метод autorizationIfCookieIsNull принимает Key, который инициализируется либо банально в контроллере
Либо в отдельном классе сервисе ClassOfKey к примеру создаём метод бин, который создаст Key, если он был равен null. При втором вызове он уже не изменится и все контроллеры получат одинаковый Key
Ещё этот метод принимает HttpServletResponse из которого мы достаём куки (40, 78 стр)
Далее идут логин и пароль. Пароль может быть и строкой. Зависит только от вашей фантазии и метода сервиса Spring Data разумеется. В моём случае это число
Внутри метода мы вызываем коллекцию из 1 пользователя
Далее находим роль пользователя. Метод называется getRoleId потому, что таблица пользователи имеет зависимость к таблице роли и ищутся роли по колонке id в таблице пользователи.
Здесь в коллекцию role пытаемся добавить объекты. Потом идёт проверка вернул ли сервис пользователя, если да то он существует и проверяем его пароль и роль.
Так же в проекте используется фреймворк JJWT https://github.com/jwtk/jjwt вся документация там. Фреймворк под лицензией Apatch 2.0 поэтому в шапке класса нужно написать комментарий:
Copyright [2021] [jwtk] Licensed under the Apache License, Version 2.0 (the «License»)
В метод setSubject кладём логин и пароль через пробел, а в метод signWith кладём ключ( пример стр. 49 ). Получившийся токен представлен в виде строки. Пример:
0LrRgdC40LwgMTIzIn0.a90QRs3CBRxEzfgezWetBvjozb8btfXFahmrsgSe8Jc
Данные до точки это зашифрованные данные, а после ключ. Эта строка добавляется в cookie с заголовком JWT например
Далее устанавливается время жизни токена примерно на месяц
И передаём cookie в глобальную переменную
Ну и логично, что в методе контроллера нам нужно дополнительно вызывать метод для извлечения cookie из класса фильтра. Изначально весь этот код лежал в контроллере. Пришлось положить в отдельные классы чтобы не наговнокодить
Если авторизация была неудачной, вернётся страница регистрации autorizationErr.html с текстом возможной ошибки
Третий метод похож на первый поэтому рассмотрим только второй. Стоит так же отметить, что весь процесс извлечения строки происходит в блоке try, потому что если ключ не подходит генерируется ошибка JwtException. В методе находим тело cookie записи по заголовку. Извлечённую строку подставляем в монолитную конструкцию и получаем строку с логином и паролем через проблем. Применяем
и получаем массив из двух строк. Также преобразуем пароль в Integer
Честно говоря легче было сделать пароль в виде строки, но что сделано то сделано. Оставлю это здесь может пригодится. Ну и точно также проверяем дынные на действительность.
Это мы рассмотрели только класс фильтр авторизации. Нужно ещё рассмотреть класс фильтра аутентификации других страниц. Покажу пример класса фильтра который установлен и работает при запросе главной страницы домена например ursite.com/
Как можно заметить метод autentification абсолютно похож на одноименный метод в 1 классе фильтре. При проверке данных токена происходит редирект в соответствии с ролью. Этот класс можно переиспользовать на любой странице и любой роли которую вы захотите создать следующим образом
Необходимые зависимости в pom файле