Широ в приложении Java EE 6

Я следовал коду BalusC для управления аутентификацией пользователей в Java EE 6 (http://balusc.blogspot.com/2013/01/apache-shiro-is-it-ready-for-java-ee-6.html), который работает отлично, если я останусь в том же веб-контейнере.

Я столкнулся с проблемой, которая, возможно, кто-нибудь может мне помочь. При внедрении EJB, который находится в веб-контейнере, SecurityUtils.getSubject() работает нормально из любого метода этого EJB.

Проблема в том, что когда я пытаюсь сделать это на внедренном EJB из другого контейнера (даже на ejb jar в том же EAR).

The error I get is:

Вызвано: org.apache.shiro.UnavailableSecurityManagerException: нет SecurityManager, доступного для вызывающего кода, либо привязанного к org.apache.shiro.util.ThreadContext, либо как статический синглтон vm. Это недопустимая конфигурация приложения.

The use case is:

Управляемый bean-компонент A с внедренным сеансовым bean-компонентом без сохранения состояния B. Класс A находится в myApp.war, класс B находится в myApp.ejb, оба внутри myApp.ear. Я звоню SecurityUtils из класса B.

Есть ли у вас какие-либо подсказки о том, как решить эту проблему?

Я использую JSF 2, Java EE 6, JBoss 7.1.


person Rafael Sisto    schedule 20.08.2013    source источник


Ответы (2)


Я сам отвечаю на вопрос.

Я решил интеграцию с помощью фильтра и пользовательского модуля входа в систему для JBoss:

Фильтр (должен применяться после вызова фильтра широ):

public class ShiroJAASIntegrationFilter implements Filter{

    static Logger logger = Logger.getLogger(ShiroJAASIntegrationFilter.class);
    @Override
    public void destroy() {
    }

    @Override
    public void doFilter(ServletRequest arg0, ServletResponse arg1,
            FilterChain arg2) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest)arg0;
        Principal userPrincipal = httpServletRequest.getUserPrincipal();
        HttpSession session = httpServletRequest.getSession(false);
        if(userPrincipal!=null){
            if(session!= null && session.getAttribute("shiroAuthenticated")==null){
                String name = userPrincipal.getName();
                try {
                    httpServletRequest.login(name,"");
                    session.setAttribute("shiroAuthenticated",true);
                } catch (ServletException e) {
                    logger.debug("Unable to authenticate user" + e.getMessage());
                }
            }

        }
        arg2.doFilter(arg0, arg1);
    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {
    }
}

Модуль входа, он просто устанавливает пользователя как аутентифицированного:

public class ShiroJAASLoginModule extends UsernamePasswordLoginModule {

    /**
     * Always return true. 
     */
    protected boolean validatePassword(String inputPassword,
            String expectedPassword) {
        return true;
    }

    protected Group[] getRoleSets() throws LoginException {
        //TODO: if needed, add roles
        Group[] roleSets = { new SimpleGroup("Roles") };
        roleSets[0].addMember(new SimplePrincipal(getUsername()));
        return roleSets;
    }


    @Override
    protected String getUsersPassword() throws LoginException {
        return null;
    }

}

Модуль должен быть определен в файле standalone.xml:

<security-domain name="shiro" cache-type="default">
 <authentication>
  <login-module code="web.security.shiroJaasIntegration.ShiroJAASLoginModule" flag="required"/>
 </authentication>
</security-domain>

Наконец, определите домен безопасности в ваших приложениях jboss-web.xml:

<jboss-web>
    <security-domain>shiro</security-domain>

</jboss-web>
person Rafael Sisto    schedule 25.08.2013
comment
Я сталкиваюсь с тем же исключением. Вы помните, что конкретно вызвало проблему и как этот код решает ее? - person Jens Piegsa; 18.05.2017

Итак, Широ связывает SecurityManager как ThreadLocal через ShiroFilter. Посмотрите на метод doFilterInternal. Subject привязан к ThreadContext только внутри метода subject.execute, что означает, что SecurityUtils.getSubject() будет возвращать null каждый раз, когда он будет вызываться вне subject.execute, что означает вне ShiroFilter, что означает внешняя нить запроса< /strong> и это проблема, я думаю.

AbstractShiroFilter.java

protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse, final FilterChain chain)
            throws ServletException, IOException {
...

            final Subject subject = createSubject(request, response);

            //noinspection unchecked
            subject.execute(new Callable() {
                public Object call() throws Exception {
                    updateSessionLastAccessTime(request, response);
                    executeChain(request, response, chain);
                    return null;
                }
            });    
...
    } 

Ну, вы сказали, что inject Stateless B какова ваша структура DI? Широ может легко интегрироваться с Guice и Spring.

person Milan Baran    schedule 20.08.2013
comment
Привет, спасибо за ваш вклад. Я использую EJB3.1 с JSF2 и в данный момент не могу переключиться на Guice или Spring. На самом деле ejb вызывается в том же потоке широфильтра, не знаю, почему когда дело доходит до стека проекта EJB3.1, Широ ThreadLocal пропадает.. Возможно, я могу добавить его вручную с помощью второго фильтра, но возможно, это проблема со стеком EJB. - person Rafael Sisto; 20.08.2013