2012-05-08 11 views
4

Я пытаюсь использовать Apache Shiro с Spring и MongoDB. Я использую Spring Data Repositories, которые являются autwired. Я создал свою собственную область для Shiro, который использует хранилище данных Spring, чтобы поговорить с Монго:Spring MongoDB и Apache Shiro

public class PlatformRealm extends AuthorizingRealm { 

    @Autowired(required = true) 
    protected UserRepository userRepository = null; 

    @Override 
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { 
     ... 
    } 
} 

Проблемой я вижу это userRepository не будучи autowired. Я получаю следующую строку в моей консоли вывода со ссылкой на PlatformRealm:

INFO org.springframework.web.context.support.XmlWebApplicationContext - Bean 'platformRealm' of type [class com.resonance.platform.core.security.PlatformRealm] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying) 

Это происходит из-за Apache Shiro ShiroFilterFactoryBean. То, что происходит, это этот компонент, и все его зависимости загружаются сразу же после запуска контейнера. Это не дожидается, когда мои персистентные компоненты будут инициализированы до разрешения зависимостей. Это приводит к тому, что ссылка репозитория будет равна нулю.

следующие конфигурации фасоли загружаются с помощью параметра contextConfigLocation:

<context-param> 
    <param-name>contextConfigLocation</param-name> 
    <param-value> 
     /WEB-INF/web-platform-persistence.xml, 
     /WEB-INF/web-platform-services.xml 
    </param-value> 
</context-param> 

Услуги конфигурации фасоли:

<beans xmlns="http://www.springframework.org/schema/beans" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" 
xmlns:util="http://www.springframework.org/schema/util" 
xsi:schemaLocation="http://www.springframework.org/schema/context 
     http://www.springframework.org/schema/context/spring-context-3.0.xsd 
     http://www.springframework.org/schema/beans 
     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
     http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd"> 

<bean id="userSession" 
    class="com.resonance.platform.web.core.services.ShiroUserSessionService" /> 

<!-- Shiro (Security) --> 
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> 
    <property name="securityManager" ref="securityManager" /> 
    <property name="loginUrl" value="/login" /> 
    <property name="successUrl" value="/" /> 
    <!-- The 'filters' property is not necessary since any declared javax.servlet.Filter 
     bean --> 
    <!-- defined will be automatically acquired and available via its beanName 
     in chain --> 
    <!-- definitions, but you can perform instance overrides or name aliases 
     here if you like: --> 
    <!-- <property name="filters"> <util:map> <entry key="anAlias" value-ref="someFilter"/> 
     </util:map> </property> --> 
    <property name="filterChainDefinitions"> 
     <value> 
      # some example chain definitions: 
      /admin/** = passThruFilter, roles[admin] 
      /** = passThruFilter 
     </value> 
    </property> 
</bean> 

<bean id="passThruFilter" 
    class="org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter" /> 

<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> 
    <!-- Single realm app. If you have multiple realms, use the 'realms' property 
     instead. --> 
    <property name="realm" ref="platformRealm" /> 
    <!-- By default the servlet container sessions will be used. Uncomment 
     this line to use shiro's native sessions (see the JavaDoc for more): --> 
    <!-- <property name="sessionMode" value="native"/> --> 
</bean> 

<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /> 

<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" 
    depends-on="lifecycleBeanPostProcessor" /> 

<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> 
    <property name="securityManager" ref="securityManager" /> 
</bean> 

<!-- Define the Shiro Realm implementation you want to use to connect to 
    your back-end --> 
<!-- security datasource: --> 
<bean id="platformRealm" class="com.resonance.platform.core.security.PlatformRealm" /> 

Постоянство фасоли конфигурации:

<beans xmlns="http://www.springframework.org/schema/beans" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" 
xmlns:mongo="http://www.springframework.org/schema/data/mongo" 
xmlns:util="http://www.springframework.org/schema/util" 
xsi:schemaLocation="http://www.springframework.org/schema/context 
     http://www.springframework.org/schema/context/spring-context-3.0.xsd 
     http://www.springframework.org/schema/data/mongo 
     http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd 
     http://www.springframework.org/schema/beans 
     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
     http://www.springframework.org/schema/util 
     http://www.springframework.org/schema/util/spring-util-3.0.xsd"> 

<mongo:mongo id="mongo" /> 

<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"> 
    <constructor-arg ref="mongo" /> 
    <constructor-arg value="platform" /> 
    <property name="writeConcern"> 
     <util:constant static-field="com.mongodb.WriteConcern.SAFE" ></util:constant> 
    </property> 
</bean> 

<mongo:repositories base-package="com.resonance.platform.core.data.repositories" /> 

Пользователь Repository:

package com.resonance.platform.core.data.repositories; 

import org.bson.types.ObjectId; 
import org.springframework.data.repository.CrudRepository; 

import com.resonance.platform.core.entities.User; 

/** 
* A repository used to manage User entities. 
* @author Kyle 
*/ 
public interface UserRepository extends CrudRepository<User, ObjectId> { 

    /** 
    * Gets a user by the specified login. 
    * @param login 
    * @return 
    */ 
    User getByLogin(String login); 

} 

Мой вопрос, как я могу получить зависимость userRepository чтобы решить правильно? Я понимаю, что ShiroFilterFactoryBean должен быть инициализирован до других зависимостей и еще чего-то, но должен быть способ, чтобы получить зависимость userRepository.

EDIT: Добавлен код репозитория пользователя.

+0

Можете ли вы опубликовать код в своем UserRepository? – sourcedelica

+0

Я полагаю, это просто интерфейс, поскольку платформа Spring's Data автоматически создает фактическую реализацию. – SoWeLie

+0

Загружаются ли файлы spring.xml как часть одного и того же времени выполнения ApplicationContext? Или одна часть контекста приложения, а другая часть файла foo-servlet.xml? –

ответ

1

Если вы правильно поняли, вы должны быть способны создать подкласс ShiroFilterFactoryBean, который реализует org.springframework.beans.factory.InitializingBean. Затем в InitializingBean.afterPropertiesSet() вы добавите код, который получает UserRepository и устанавливает его в это поле. Не самое изящное решение, но это выглядит как исключительный случай.

+0

Проблема в том, что я не уверен, как инициализируется UserRepository. Прямо сейчас весна инициализирует его под крышками в модуле Spring Data. – SoWeLie

0

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

Но основная проблема, вероятно, остается открытой.

2

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

  1. из dispacher-servlet.xml, который загружает классы @Service @Repository из-за компонент сканирование, определенное на уровне базового пакета таким образом я могу @Autowire класса обслуживания в контроллер.
  2. из контекста приложения, похоже, не является классами @Autowire, помеченными как @Service, потому что они не загружены.
1

У меня тоже была эта проблема.Это как-то связано с порядком инициализации компонента в контейнере Spring. Обходной путь заключается не в том, чтобы autwire репозиторий, но ваша область реализует ApplicationContextAware и получает необходимые компоненты напрямую из контекста. Это не изящно, но это сработает.

0

Concrete проблема объяснения взяты из ShiroFilterFactoryBean-and-a-spring-data-mongodb-realm:

Проблема заключается в том, что весной-данных MongoDB требует весной ApplicationEventMulticaster были инициализируется, прежде чем он может быть использован .

ShiroFilterFactoryBean является beanPostProcessor, и как таковые, во время инициализации, пружинные попытки настроить его сферу (и, следовательно, мои царства и пружинные данных Монго на основе userDao). он не работает, потому что ApplicationEventMulticaster еще не создан.

После того как я попробовал несколько предложенных способы решения этой проблемы, как интерфейсы InitializingBean, ApplicationContextAware или BeanPostProcessor (каждый приводит к преждевременному вызова, поэтому перед инициализацией моих необходимых услуг/вещей хранилища), я придумал следующее решение:

  1. Позвольте весне создать свой широкий контекст без какого-либо автоматического преобразования bean-компонентов в ваши сервисы/хранилища.
  2. Позвольте весне создать контекст вашего сервиса/хранилища, включая mongodb
  3. Создайте простой класс, который позаботится о вашей шиномонтажной связи и настроит его соответствующим образом в вашей конфигурации пружины. Этот класс будет вызываться после того, как ваш сиро и контекст службы были успешно настроены.

To (1), sth. например:

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> 
    <property name="securityManager" ref="securityManager" /> 
    <property name="filterChainDefinitions"> 
     <value> 
      <!-- Your definitions --> 
     </value> 
    </property> 
</bean> 

<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" 
     p:realm-ref="myShiroRealm" /> 

<bean id="myShiroRealm" class="com.acme.MyShiroRealm" 
    <!--no bean refs here--> 
/> 

To (2), sth. как это:

<bean id="myService" class="com.acme.MyService" 
     c:myRepository-ref="myRepository" /> 

... 

<!-- Ask Spring Data to scan our repositories --> 
<mongo:repositories base-package="com.acme.repository.impl.mongodb" /> 

К (3):

public class ShiroRealmServiceBridge { 
    public static void postInject(MyShiroServerRealm realm, MyService service) { 
     realm.setService(service); 
    } 
} 

<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> 
    <property name="targetClass"><value>com.acme.ShiroRealmServiceBridge</value></property> 
    <property name="targetMethod"><value>postInject</value></property> 
    <property name="arguments"> 
    <list> 
     <ref bean="myShiroRealm" /> 
     <ref bean="myService" /> 
    </list> 
</property> 

Преимущества:

  • Он работает XD не
  • Нет дополнительной нагрузки/зависимостей на вашем Shiro вещи
  • Полная конфигурация пружины и установки, в результате чего в согласованном состоянии после инициализации

Неудобство:

  • Одна установка времени над головой
  • Может привести в неустойчивом состоянии, что будет жаловаться во время выполнения, а не на при запуске, если вы забудете или удалите конфигурацию клея
Смежные вопросы