Как я могу перехватить запрос на проверку авторизации, прежде чем произойдет создание экземпляра класса представления в веб-приложении Vaadin 14? - PullRequest
0 голосов
/ 22 января 2020

Я пытаюсь интегрировать Apache Авторизация на основе аннотаций Широ (authz) в веб-приложение Vaadin 14. Я рассмотрел некоторые общедоступные решения, касающиеся этой топи c:

Кажется, что все они используют одно и то же решение, настройте VaadinServiceInitListener, чтобы добавить BeforeEnterEvent слушатель, где должны быть реализованы все логи authz c.

Я думаю, что одна проблема возникает с таким решением:

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

Как я могу перехватить запросы до того, как будут созданы классы View, чтобы я мог выполнить правильную проверку подлинности с использованием аннотаций Широ?

Ответы [ 2 ]

2 голосов
/ 22 января 2020

В настоящее время не существует какого-либо хорошего способа перехвата запросов навигации до создания экземпляра целевого класса навигации.

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

Эта проблема была недавно решена в базовой структуре через выпуск # 4595 . Пока еще не решено, в какую версию Vaadin будут внесены изменения, поскольку в некоторых случаях они могут повлиять на обратную совместимость.

0 голосов
/ 23 января 2020

Поскольку Vaadin не предлагает «какого-либо хорошего способа перехвата запросов навигации до создания экземпляра целевого класса навигации», я выбрал длинный и извилистый путь и предложил решение на основе пользовательского Interceptor. Это позволило мне замкнуть запросы до того, как произойдет создание экземпляра класса представления, со следующими видимыми результатами:

  • Плюсы:

    • Безопасность - код не выполняется пользователями, не авторизованными для этого;

    • Производительность - поскольку я выполняю проверку подлинности ранее, все накладные расходы выполнения ненужного кода больше нет.

  • Минусы:
    • Необходимость использования дополнительной аннотации. Было бы здорово иметь решение для бесшовной интеграции с существующими аннотациями Shiro, приветствуются любые улучшения.

Решение

Добавление нового @ShiroSecured аннотация для связывания с перехватчиком:

package misc.app.security;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.interceptor.InterceptorBinding;


@Inherited
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.RUNTIME)
@InterceptorBinding
public @interface ShiroSecured { }

Добавьте ShiroSecuredInterceptor и привяжите его к ранее определенной пользовательской аннотации. Убедитесь, что метод помечен @AroundConstruct, поэтому вызовы конструктора классов, помеченные @ShiroSecured, перехватываются:

package misc.app.security;

import javax.interceptor.AroundConstruct;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;


/**
 * An interceptor for declarative security checks using the annotations from the 
 * {@code org.apache.shiro.authz.annotation} package.
 *
 */
@ShiroSecured @Interceptor
public class ShiroSecuredInterceptor extends AnnotationsAuthorizingConstructorInterceptor {

    @AroundConstruct
    public Object checkAuthorization(final InvocationContext ic) throws Exception {
        assertAuthorized(new InvocationContextToConstructorInvocationConverter(ic));

        return ic.proceed();
    }

    private static class InvocationContextToConstructorInvocationConverter implements ConstructorInvocation {

        private final InvocationContext context;


        public InvocationContextToConstructorInvocationConverter(InvocationContext ic) {
            context = ic;
        }

        @Override
        public Object proceed() throws Throwable {
            return context.proceed();
        }

        @Override
        public Class getClazz() {
            return context.getConstructor().getDeclaringClass();
        }
    }   
}

Зарегистрируйте перехватчик в beans.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans bean-discovery-mode="all" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd">

    <interceptors>
        <class>misc.app.security.ShiroSecuredInterceptor</class>
    </interceptors>
</beans>

Это суммирует основные части решения. На следующем снимке экрана перечислены все файлы классов, которые я реализовал, чтобы заставить его работать. В основном мне пришлось дублировать часть логики Широ c, относящихся к MethodInvocation, чтобы она работала для ConstructorInvocation. Два Error класса являются реализацией обработки исключений маршрутизатора Vaadin для Широ AuthorizationException и UnauthenticatedException, создаваемых при сбое проверки подлинности.

enter image description here

...