Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Основы безопасности

Сейчас удалить любой пост может кто угодно. Нужно две вещи. Аутентификация — узнать, кто прислал запрос: проверить логин и пароль. Авторизация — решить, можно ли этому пользователю то, что он просит: например, удалять посты разрешено только роли admin. В Quarkus проверки описывают стандартными аннотациями @RolesAllowed, а источник пользователей подключают расширением.

Подключение

Для учёбы возьмём самый простой источник — пользователей прямо в application.properties:

./mvnw quarkus:add-extension -Dextensions="elytron-security-properties-file"
# src/main/resources/application.properties
quarkus.security.users.embedded.enabled=true
quarkus.security.users.embedded.plain-text=true
quarkus.security.users.embedded.users.anna=changeme
quarkus.security.users.embedded.roles.anna=admin
quarkus.security.users.embedded.users.oleg=changeme
quarkus.security.users.embedded.roles.oleg=user
quarkus.http.auth.basic=true

У Анны роль admin, у Олега — user. quarkus.http.auth.basic=true включает Basic-аутентификацию: клиент отправляет логин и пароль в заголовке Authorization каждого запроса. Пароли открытым текстом годятся только для учёбы; на сервере пользователей хранят в базе с хешами паролей или используют токены (об этом в конце урока).

Защита метода

// src/main/java/com/example/blog/PostResource.java
@DELETE
@Path("/{id}")
@Transactional
@RolesAllowed("admin")
public Response delete(@PathParam("id") long id) {
    if (!Post.deleteById(id)) {
        throw new PostNotFoundException(id);
    }
    return Response.noContent().build();
}

@RolesAllowed("admin") (импорт jakarta.annotation.security.RolesAllowed) пускает только пользователей с этой ролью. Остальные методы ресурса по-прежнему открыты. Проверим три случая — без пароля, от Олега и от Анны:

curl -i -X DELETE http://localhost:8080/posts/1
curl -i -u oleg:changeme -X DELETE http://localhost:8080/posts/1
curl -i -u anna:changeme -X DELETE http://localhost:8080/posts/1
HTTP/1.1 401 Unauthorized
www-authenticate: basic

HTTP/1.1 403 Forbidden

HTTP/1.1 204 No Content

Флаг -u передаёт логин и пароль. 401 значит «не знаю, кто вы» — нужно войти. 403 — «знаю, кто вы, но вам нельзя». Неверный пароль тоже даёт 401.

Кто сделал запрос

Текущего пользователя можно получить в коде через SecurityIdentity:

// src/main/java/com/example/blog/MeResource.java
package com.example.blog;
 
import io.quarkus.security.Authenticated;
import io.quarkus.security.identity.SecurityIdentity;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
 
import java.util.Set;
 
@Path("/me")
@Authenticated
public class MeResource {
 
    @Inject
    SecurityIdentity identity;
 
    @GET
    public Me me() {
        return new Me(identity.getPrincipal().getName(), identity.getRoles());
    }
 
    public record Me(String name, Set<String> roles) {
    }
}

@Authenticated на классе пускает любого вошедшего пользователя, роль не важна.

curl -u oleg:changeme http://localhost:8080/me
{"name":"oleg","roles":["user"]}

Аннотации доступа

АннотацияКого пускает
@PermitAllВсех, даже без входа
@AuthenticatedЛюбого вошедшего пользователя
@RolesAllowed("admin")Только пользователей с ролью
@DenyAllНикого

Что используют на практике

Для настоящих API чаще берут токены: расширение oidc проверяет токены от Keycloak или другого сервера входа, smallrye-jwt — JWT-токены, подписанные вашим ключом. Аннотации @RolesAllowed и @Authenticated при этом остаются теми же — меняется только источник пользователей.

Частая ошибка

Basic-аутентификация передаёт пароль почти открытым текстом: заголовок Authorization — это просто логин и пароль в Base64, который расшифровывается за секунду. Без HTTPS его видит любой посредник в сети. Используйте Basic только локально или поверх HTTPS и не храните настоящие пароли в application.properties — этот файл попадает в Git и в собранное приложение.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.