Как получить доступ к @Named bean-компоненту в PhaseListener?

Мы используем JBoss 7.1, MySQL / PostgreSQL DB, JSF 2.0 с компонентами CDI.

Мне нужно реализовать аутентификацию на базе БД по логину и паролю. У нас есть портал управления (администрирования). Когда клиент открывает страницу с ограниченным доступом без входа в систему, он должен перенаправить запрос на страницу login.*, если клиент не вошел в систему.

Я пытался сделать это с помощью PhaseListener. Я могу войти и выйти, но когда я пытаюсь открыть другую страницу, я столкнулся с проблемой: я не могу получить компонент @Named("user") public class UserManager внутри класса PhaseListener. Я пытался получить это с помощью FacesContext, & EL ..., но все это мне не помогло.

UserManager проверяет логин и сохраняет вошедшего в систему пользователя как свойство current. По каждому запросу я хочу проверять PhaseListener, если #{user.current} не null. Но я не могу получить компонент #{user} в PhaseListener.

Как я могу получить @Named bean в beforePhase() или afterPhase()?


Обновление: вот моя попытка:

private boolean loggedIn( FacesContext context ) throws IOException, ServletException
{
    LOGSTORE.debug( "loggedIn().2 " );

    HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
    HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();

//  ELContext elContext = FacesContext.getCurrentInstance().getELContext();
//  UserManager userManager = (UserManager) FacesContext.getCurrentInstance().getApplication()
//      .getELResolver().getValue( elContext, null, "user" );

    HttpSession session = (HttpSession) context.getExternalContext().getSession( true );
    UserManager userManager = (UserManager) session.getAttribute( "user" );

//  UserManager userManager = (UserManager) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get( "user" );

    if (!StringUtils.contains( ((HttpServletRequest) context.getExternalContext().getRequest())
        .getRequestURL().toString(), URL_SESSION_EXPIRED ))
    {

        if (userManager == null || !userManager.isLoggedIn())
        {
            LOGSTORE.debug( " userManager is " + (userManager == null ? "" : "not ") + " null" );
            if (userManager != null)
            {
                LOGSTORE.debug( " userManager.isLoggedIn() is "
                    + (userManager.isLoggedIn() ? "TRUE" : "FALSE") );
            }
            LOGSTORE.debug( " doPhaseFilter() - START REDIRECT " );
            response.sendRedirect( request.getContextPath() + "/" + homepage + "?auth-failed" );
        }
        return false;

    } else
    {
        LOGSTORE.debug( "loggedIn().3 it is " + homepage );
        return true;
    }
}

person abn_java    schedule 23.01.2012    source источник
comment
Пожалуйста, покажите код, который вы пробовали, когда вы сказали я пытался получить его с помощью FacesContext, & EL ..., что все мне не помогло   -  person BalusC    schedule 23.01.2012
comment
Я добавил выше фрагмент, в котором я пытаюсь получить bean-компонент в SessionPhaseListener   -  person abn_java    schedule 23.01.2012


Ответы (4)


Управляемый bean-компонент CDI с ограниченным сеансом не сохраняется в HTTP-сеансе так же, как обычный управляемый JSF-компонент с ограниченным сеансом. Управляемый JSF с ограниченным объемом сеанса действительно хранится в сеансе по имени компонента в качестве ключа. Однако управляемый bean-компонент CDI с областью действия сеанса абстрагируется дальше через другую карту в области действия сеанса.

Вам нужно получить его, оценив EL программно, а не извлекая его из карты сеанса. Ваша попытка преобразователя EL содержит одну ошибку: значение не содержит выражения #{}.

ELContext elContext = FacesContext.getCurrentInstance().getELContext();
UserManager userManager = (UserManager) FacesContext.getCurrentInstance().getApplication()
    .getELResolver().getValue(elContext, null, "user");

Исправьте это соответствующим образом:

ELContext elContext = FacesContext.getCurrentInstance().getELContext();
UserManager userManager = (UserManager) FacesContext.getCurrentInstance().getApplication()
    .getELResolver().getValue(elContext, null, "#{user}");

Между прочим, сокращение для вышеупомянутого - Application#evaluateExpressionGet():

UserManager userManager = context.getApplication()
    .evaluateExpressionGet(context, "#{user}", UserManager.class);

Обратите внимание, что у вас уже есть FacesContext context в качестве аргумента метода.

person BalusC    schedule 24.01.2012
comment
Чудесно! Я напрасно пробовал всякие всякие штуки, используя только этот пример ссылка. Теперь я могу спать! Еще раз спасибо BalusC. - person Ravi Kadaboina; 24.03.2012

Я использую следующий код, чтобы получить ссылку на компоненты CDI из PhaseListener.

public BeanManager getBeanManager() {
    BeanManager beanManager = null;
    try {
        InitialContext initialContext = new InitialContext();
        beanManager = (BeanManager) initialContext.lookup("java:comp/BeanManager");
    } catch (NamingException e) {
        logger.log(Level.SEVERE, "Couldn't get BeanManager through JNDI", e);
    }
    return beanManager;
}

public <T> T getBean(final Class<T> clazz) {
    BeanManager bm = getBeanManager();
    Bean<T> bean = (Bean<T>) bm.getBeans(clazz).iterator().next();
    CreationalContext<T> ctx = bm.createCreationalContext(bean);
    return (T) bm.getReference(bean, clazz, ctx);
}

Итак, чтобы получить bean-компонент, вы бы назвали его следующим образом.

DataManager dataManager = getBean(DataManager.class);

В этом случае bean-компонент - это bean-компонент @Dependent, который используется в PhaseListener.

person John Yeary    schedule 20.12.2012

Надеюсь, это будет исправлено в следующей версии JSF, которая имеет реальную интеграцию с CDI для этого. Что вам нужно сделать (и сохранить переносимость), так это найти BeanManager через JNDI, а затем получить именованный bean из BeanManager.

person LightGuard    schedule 24.01.2012

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

person Roland Tiefenbrunner    schedule 17.02.2012