Простой сервис аутентификации. SpringBootSecurity
GitLab
Напишем простой сервис аутентификации с выдачей JWToken. Для реализации будем использовать Java 17, SpringBoot 3.2.0, h2, Maven в памяти.
Cоздадим и настроим проект https://start.spring.io/
SpringInitializer
Нам понадобится:
Web
Security
JPA
H2 Database
Lombok
Настроим подключение к нашей БД которая будет находится в памяти, так же сервер будем запускать на порту 9090
application.properties
Для автоматического заполнения БД создадим пару файлов с созданием и заполнением таблиц data.sql и schema.sql.
Содержание файлов data && schema
data.sql
schema.sql
Далее нам потребуется создать сопутствующие сущности User, Role
User
Role
Закончили с базовой настройкой, переходим к основному классу WebConfiguration настройки Security. В нем мы должны настроить bean SecurityFilterChain, так же создадим bean PasswordEncoder для возможности шифрования пароля пользователя.
WebConfiguration.jav
Для шифрование пароля будем использовать BCrypt.
Далее рассмотрим SecurityFilterChain:
http.headers (headers → headers.frameOptions (HeadersConfigurer.FrameOptionsConfig: sameOrigin))
.csrf (AbstractHttpConfigurer: disable)
.cors (AbstractHttpConfigurer: disable);
В этой строчке мы отключаем CSRF && CORS так как для простого фунционала нам они не понадобятся.
В проде обязательно использовать CSRF && CORS
Т.к h2-console использует frame то для корректной работы нужно добавить header x-frame-options «SAMEORIGIN» или отключить его FrameOptionsConfig: disable
X-Frame-Options используется для предотвращения кликджекинга на сайте. Он определяет, разрешено ли браузеру отображать страницу в ,
headers.frameOptions (HeadersConfigurer.FrameOptionsConfig: disable)
OR
headers.frameOptions (HeadersConfigurer.FrameOptionsConfig: sameOrigin)
Далее разрешим доступ к консоли h2 для всех пользователей и для остальных запросов требуется аутентификация
http.authorizeHttpRequests (authz →
authz.requestMatchers (»/h2-console/**»).permitAll ().anyRequest ().authenticated ());
Главное действие будет происходить в фильтрации запроса
http.addFilterAt (initialAuthenticationFilter, BasicAuthenticationFilter.class);
Здесь мы добавляем свой фильтр в цепочку фильтрации initialAuthenticationFilter который мы inject’им в методе
public SecurityFilterChain securityFilterChain (HttpSecurity http, InitialAuthenticationFilter initialAuthenticationFilter)
InitialAuthenticationFilter.java
Данный класс будет расширять OncePerRequestFilter и переопределять два метода
doFilterInternal
shouldNotFilter
Данный фильтр проверяет header Authorization, если он пустой то проверяет передано ли в теле запроса JSON с именем и паролем для аутентификации, проверят пользователя и если все ок выдает JWToken.
Рассмотрим более подробно данный класс.
Для формирования JWToken и проверки пользователя создадим и заинжектим два класса
private final JwtService jwtService;
private final UsernamePasswordAuthenticationProvider authenticationProvider;
JwtService.java
Для работы с JWT потребуются следующие библиотеки
pom.xml
Здесь мы будем генерировать ключ подписи и собственно сам JWT.
Keys.hmacShaKeyFor (signingKey.getBytes (StandardCharsets.UTF_8));
шифруем ключ BASE64
В методе generatedJwt строим JWT.
Задаем поля в payload и нагрузку, устанавливаем дату окончания действия и ключ подписи
payload {
"role"
"user_id
"username"
"exp"
"sub"
}
UsernamePasswordAuthenticationProvider.java
Данный класс проверяет наличие пользователя и корректность пароля и возвращает аутентификацию.
Класс UserDetailsService возвращает пользователя если он имеется в базе
UserService.java
Вернемся к классу InitialAuthenticationFilter.
Метод doFilterInternal
из request мы извлекаем JSON с логином и паролем
проеряем пользователя
Authentication authentication = new UsernamePasswordAuthentication (username, password); authentication = authenticationProvider.authenticate (authentication);если все ок выдаем JWT в response в заголовок Authorization: Bearer *****
String jwt = jwtService.generatedJwt (authentication); response.setHeader («Authorization», HeaderValues.BEARER + jwt);
Метод shouldNotFilter
Проверка
curl -v -d '{«username»: «admin», «password»:»123»}' -H «Content-Type: application/json» -X POST http://localhost:9090/login
Видим, что появился header
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjpbIlJPTEVfQURNSU4iLCJST0xFX1VTRVIiXSwidXNlcl9pZCI6IjEiLCJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzAzMTU1NzAxLCJzdWIiOiJhZG1pbiJ9.aNHtaBa-7WDXO_MMl83MG9wxTO0MnMmEwdjgzSOrh0g
Содержание JWToken
Данный пример демонстрирует как достаточно быстро и просто поднять сервис аутентификации и выдачи JWT. Так же можно добавить проверку токена, выдача refresh token и запрос со стороннего сервиса, но это уже другая история.