Ответ
Процесс получения JWT (JSON Web Token) следует стандартному flow аутентификации:
Основные шаги:
-
Клиент отправляет учетные данные.
- Обычно
POST-запрос на эндпоинт/loginили/oauth/token. - Тело запроса содержит
username/password,client_id/client_secret(для OAuth2) или refresh token.POST /api/auth/login HTTP/1.1 Content-Type: application/json { "username": "user@example.com", "password": "secure_password" }
- Обычно
-
Сервер аутентификации проверяет данные.
- Валидирует логин/пароль в БД или через внешний провайдер (LDAP, OIDC).
- Проверяет активность учетной записи и права доступа.
-
Сервер генерирует и подписывает JWT.
- Header: Определяет алгоритм подписи (например,
HS256илиRS256). - Payload (Claims): Содержит данные (sub, roles,
exp— время истечения,iat— время выдачи). - Signature: Создается путем подписи
header.payloadсекретным ключом (HMAC) или приватным ключом (RSA).
- Header: Определяет алгоритм подписи (например,
-
Сервер возвращает токен клиенту.
- Чаще всего в теле ответа как JSON-объект.
{ "access_token": "eyJhbGciOiJIUzI1NiIs...", "token_type": "Bearer", "expires_in": 3600 }
- Чаще всего в теле ответа как JSON-объект.
Пример на Spring Security (упрощенно):
// Конфигурация сервера (используя Password Grant)
@Configuration
@EnableAuthorizationServer
public class AuthConfig extends AuthorizationServerConfigurerAdapter {
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("clientapp")
.secret(passwordEncoder().encode("secret"))
.authorizedGrantTypes("password", "refresh_token")
.scopes("read", "write");
}
}
// Клиентский запрос (с помощью RestTemplate или WebClient)
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth("clientapp", "secret");
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
body.add("grant_type", "password");
body.add("username", "user");
body.add("password", "pass");
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(body, headers);
ResponseEntity<Map> response = restTemplate.postForEntity(
"http://auth-server/oauth/token",
request,
Map.class
);
String jwt = (String) response.getBody().get("access_token");
Best Practices:
- Всегда используйте HTTPS.
- Храните секретные ключи в безопасном хранилище (не в коде).
- Устанавливайте разумное время жизни токена (
expires_in). - Для хранения на клиенте предпочтительны HttpOnly, Secure куки.
Ответ 18+ 🔞
А, слушай, смотри, про эти ваши JWTшки, ну, это ж классика, блядь, как два пальца обоссать! Весь этот цирк с аутентификацией, он по одному и тому же сценарию, как по нотам, пиздец.
Ну, короче, вот как это обычно происходит, по шагам, чтобы даже мартышке понятно было:
-
Клиент, этот, лезет, сука, со своими данными.
- Тыкает
POST-запросом куда-нибудь в/loginили, там, в/oauth/token, если он такой весь из себя продвинутый. - И суёт в тело, понимаешь, либо логин с паролем, либо
client_idсо своим секретом, либо, если он уже не первый день живёт, refresh token свой потрёпанный.POST /api/auth/login HTTP/1.1 Content-Type: application/json { "username": "user@example.com", "password": "secure_password" }
- Тыкает
-
Сервер аутентификации, этот важный бугай, начинает проверять.
- Лезет в базу, смотрит: а есть ли такой юзер, и совпадает ли хэш пароля, а то мало ли, блядь, кто пришёл. Или там в LDAP стучится, или к OIDC-провайдеру.
- Заодно глядит, не заблочили ли аккаунт и какие у него там права, чтобы не дай бог куда не надо полез.
-
А вот тут, сука, начинается магия! Сервер генерирует токен.
- Header (Заголовок): Тут пишут, какой алгоритм подписи, типа
HS256илиRS256. Чтоб все знали, как проверять. - Payload (Данные, они же claims): А это самое вкусное! Сюда пихают всё: кто (
sub), какие роли, когда истечёт (exp— это святое, блядь!), когда выпущен (iat). - Signature (Подпись): А это, блядь, чтобы не подделали! Берут
header.payload, и ебут их секретным ключом (если HMAC) или приватным ключом (если RSA). Получается этакая криптографическая печать, в рот меня чих-пых!
- Header (Заголовок): Тут пишут, какой алгоритм подписи, типа
-
И сервер, довольный как слон, отдаёт токен обратно.
- Обычно в JSON-объекте, чтоб красиво было.
{ "access_token": "eyJhbGciOiJIUzI1NiIs...", "token_type": "Bearer", "expires_in": 3600 }Всё, клиент с этим токеном, как с гранатой, бегает по API.
- Обычно в JSON-объекте, чтоб красиво было.
Ну, а если на Spring Security, то вот, смотри, упрощённо, как это выглядит, ёпта:
// Конфигурация сервера (используя Password Grant)
@Configuration
@EnableAuthorizationServer
public class AuthConfig extends AuthorizationServerConfigurerAdapter {
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("clientapp")
.secret(passwordEncoder().encode("secret"))
.authorizedGrantTypes("password", "refresh_token")
.scopes("read", "write");
}
}
// Клиентский запрос (с помощью RestTemplate или WebClient)
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth("clientapp", "secret");
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
body.add("grant_type", "password");
body.add("username", "user");
body.add("password", "pass");
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(body, headers);
ResponseEntity<Map> response = restTemplate.postForEntity(
"http://auth-server/oauth/token",
request,
Map.class
);
String jwt = (String) response.getBody().get("access_token");
И главное, блядь, не накосячь с безопасностью, запомни раз и нахуй:
- HTTPS — это не обсуждается, ёпта! Без него — ты просто раздаёшь свои данные всем подряд, как мудак.
- Ключи, эти секретные, храни не в коде, а в нормальном хранилище (Vault, KMS), а то будет овердохуища стыда.
- Время жизни токена (
expires_in) ставь адекватное. Не на год, блядь, но и не на пять минут, чтобы пользователь не взбесился. - На клиенте лучше всего токен в HttpOnly, Secure куки пихать. В localStorage — это как оставлять ключи от квартиры под ковриком, пидарас шерстяной.