Лекция 13-14

Тема: Понятие сессии. Cookies. JWT-токены. Генерация токенов. Security Filter Chain. Разработка приложения с использованием jwt-токенов.

  1. Добавляем в pom-файл поддержку jwt и jaxb

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.1</version>
</dependency>

Создадим класс JwtUtils, добавим приватный ключ и методы для создания токена

@Service
public class JwiUtil {

    private String PRIVATE_KEY = "670d4918c206e1bfec75bcaf637dc5b8";

    private String generateToken(UserDetails userDetails) {
        Map<String, Object> claims = new HashMap<>();
        return createToken(claims, userDetails.getUsername());
    }

    private String createToken(Map<String, Object> claims, String subject) {
        return Jwts.builder()
                .setClaims(claims)
                .setSubject(subject)
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 8))
                .signWith(SignatureAlgorithm.HS512, PRIVATE_KEY).compact();
    }
}

Добавим метод для валидациия токена и сопутствующие ему методы

Создадим классы-обертки для входящего логина и пароля и для исходящего jwt

Создадим класс REST-контроллера, добавим метод для создания токена. Логика работы метода следующая:

  1. Производится аутентификация по пришедшему логину и паролю;

  2. Если аутентификация прошла успешно, то получаем UserDetails из БД по username;

  3. Генерируем токен с помощью данных UserDetails;

  4. Возвращаем токен как объект AuthResponse.

Настраиваем конфигурационный класс SecurityConfig. Добавляем bean для AuthenticationManager, а также доступ к URL. Для того, чтобы сервер не генерировал новую сессию, устанавливаем sessionCreationPolicy.

В качестве клиента используем Postman.

Для начала попробуем сделать запрос с некорректным логином и паролем

На стороне сервера было выброшено исключение

Теперь попробуем ввести логин и пароль существующего пользователя. В ответ мы получим jwt, который будем использовать для последующих запросов.

Аутентификация с помощью jwt

Добавим в класс-контроллер endpoint, для доступа к которому требуется аутентификация. Входной аргумент типа Principal хранит информацию об аутентифицированном пользователе. Получаем username пользователя и извлекаем из БД информацию о нем.

Редактируем конфигурационный класс SecurityConfig, добавляем требование аутентификации для endpoint /helloworld.

Для того чтобы провести аутентификацию с помощью jwt, создадим отдельный фильтр, который потом встроим в filter chain, которая используется в Spring Security.

Логика работы нашего фильтра следующая:

  1. Считываем заголовок GET-запроса с ключом "Authorization";

  2. Проверяем, есть ли в начале заголовка слово "Bearer ";

  3. Извлекаем из jwt значение username;

  4. Извлекаем из БД пользователя по полученному username и осуществляем валидацию токена;

  5. Если jwt провел валидацию, то аутентифицируем пользователя;

  6. Передаем управление дальше по цепочке фильтров.

Отредактируем конфигурационный класс SecurityConfig, добавим использование фильтра в цепочке фильтров (мы указываем, что наш фильтр должен быть встроен в цепочку ДО фильтра UsernamePasswordAuthenticationFilter, который является стандартным фильтром для аутентификации).

Last updated

Was this helpful?