Внедрение совместной проверки подлинности в веб-приложении Java

У меня есть требование создать веб-приложение на основе Java, где ресурс должен быть доступен только тогда, когда во все авторизованные пользователи этого ресурса войдут. Кроме того, если какой-либо авторизованный пользователь выходит из системы, этот ресурс больше не будет доступен к любому из них.

Ресурс может быть любого типа (html-страницы, pdf-документы, распространенные листы и т.д.).

Существуют ли существующие стандарты/протоколы аутентификации, поддерживающие этот тип требований, или я должен создать это с нуля?

Ответ 1

ресурс должен быть доступен только тогда, когда все авторизованные пользователи этого ресурса войдут в систему. Кроме того, если какой-либо авторизованный пользователь выходит из системы, ресурс больше не будет доступен никому из них.

После того, как вы предоставили пользователю доступ к ресурсу, этот пользователь сможет загружать/снимать скриншоты/сохранять/записывать ресурс, независимо от того, является ли это PDF-документ, изображение, аудиофайл. Я не знаю контекста и цели того, что вы пытаетесь построить, но вы должны знать, что в любом случае это будет неуверенно.

Даже отложив это внимание, вам понадобится решение в реальном времени. После того, как пользователь загрузил страницу, содержащую ресурс, вы должны иметь возможность скрывать или запрещать ему права на изменение. Это означает, что вы должны использовать что-то вроде WebSockets или Ajax Polling на стороне клиента, чтобы знать интерфейс, когда ваш сервер считает, что не все необходимые пользователи подключены к сети и что доступ к ресурсу должен быть "отклонен". Но еще раз, так как это клиентский код, его можно легко изменить или изменить, запросы, которые он отправляет, могут быть легко заблокированы пользователем, поэтому он снова по своей сути небезопасен.

Я бы предложил немного обсудить контекст и описать, в чем проблема, которую вы пытаетесь решить, потому что, скорее всего, существует более разумное решение для ее решения.

Если вам нужно отказаться от прав модификации, если не все "владельцы ресурсов" находятся в сети, это легче выполнить, поскольку изменения будут выполняться на стороне сервера. В этом случае решение с использованием WebSockets может быть легко реализовано, но я не знаю библиотеки или фреймворка, которые делают такую ​​вещь. Скорее всего, вам придется самостоятельно его строить.

Ответ 2

Если вы не можете использовать определенную веб-инфраструктуру, не стесняйтесь попробовать следующую реализацию на основе фильтра для трикотажа. Обратите внимание, что вам по-прежнему необходимо добавить достаточное количество настраиваемого кода для обработки логики "коллективной проверки подлинности", поскольку трикотаж предоставляет только основные инструменты, необходимые для этого, и он явно не реализует всю концепцию. Вот как вы могли это сделать, на высоком уровне:

class AuthorizationProvider {

    public void authenticate(ContainerRequestContext requestContext) {

        // Here you would need to query your database to get the Collection of Users belonging 
        // to the "Collective" Role. You would then check if they are all logged in.
        // A really abstract version would look like this, assuming you've already queried the DB
        // and have a reference to the above mentioned Collection.

        if (collectiveUsers.size == collectiveUsers.stream().filter(User::isLoggedIn).count()) {
            return true;
        }
        return false;
    }
}

class AuthorizationRequestFilter implements ContainerRequestFilter {

    private final AuthorizationProvider authorizationProvider;

    @Override
    public void filter(ContainerRequestContext requestContext) {

        if (authorizationProvider.authenticate(requestContext)) {
            // serve whatever it is you want to serve if all required users are logged in
        } else {
            // otherwise reject the request
            requestContext.abortWith(Response
                .status(Response.Status.UNAUTHORIZED)
                .entity("Resource available only after collective login")
                .build());
        }
    }
}

@ApplicationPath("/")
class MyApplication extends ResourceConfig {

    public MyApplication() {
        // Register the filter
        register(AuthorizationRequestFilter.class);
    }
}

Кроме того, вам также потребуется обработать часть входа. Вы назначили этим конкретным пользователям коллективную роль, и вы пометили бы их как выполненные в журнале, когда они успешно пройдут аутентификацию входа в систему.

Если все вышеуказанные условия выполнены, вы должны иметь возможность успешно обслуживать страницу "Только для коллективного использования", только когда все "Коллективные" пользователи вошли в систему.

Это также охватывает часть, в которой, если один из этих пользователей выходит из системы, вы сохраняете состояние в своей базе данных (отметьте коллективный пользователь isLoggedIn = false). Поэтому с этого момента, когда кто-то запрашивает страницу, он будет возвращать Unauthorized.

И наоборот, вы также можете попытаться реализовать SSE (события, отправленные сервером), чтобы активно обновлять внешнюю часть, если кто-то выходит из системы. При этом страница будет активно отключена, даже если кому-то уже удалось ее получить ранее.

Источник и пример источника запроса контейнера, для справки, jersey docs