4

Spring と MongoDB で Apache Shiro を使用しようとしています。自動配線されたSpring Data Repositoriesを使用しています。Spring Data リポジトリを使用して Mongo と通信する Shiro 用の独自のカスタム レルムを作成しました。

public class PlatformRealm extends AuthorizingRealm {

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

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

私が見ている問題は、userRepository が自動配線されていないことです。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 によるものです。何が起こっているかというと、この Bean とそのすべての依存関係は、コンテナーが開始されるとすぐにロードされます。依存関係を解決する前に永続化 Bean が初期化されるのを待ちません。これにより、リポジトリ参照が null になります。

次の Bean 構成は、 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> 

サービス Bean の構成:

<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" />

永続性 Bean の構成:

<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" />

ユーザー リポジトリ:

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 依存関係を解決する方法が必要です。

編集: ユーザー リポジトリ コードを追加しました。

4

6 に答える 6

2

ここで説明したのと同じ問題が発生しています。スプリング工場が 2 つあることに気付きました。

  1. 基本パッケージレベルで定義されたコンポーネントスキャンにより @Service @Repository クラスをロードする dispacher-servlet.xml から、@Autowire Service クラスを Controller に接続できます。
  2. from application context は、ロードされていないため、 @Service としてマークされた @Autowire クラスには見えません。
于 2012-09-12T18:53:40.750 に答える
1

ShiroFilterFactoryBean私があなたを正しく理解していれば、そのサブクラスを作成できるはずですorg.springframework.beans.factory.InitializingBean。次に、 を取得してそのフィールドに設定するInitializingBean.afterPropertiesSet()コードを追加します。UserRepository最も洗練されたソリューションではありませんが、これは例外的なケースのようです。

于 2012-05-18T18:06:28.733 に答える
0

これが役立つかどうかはよくわかりませんが、別の解決策については、私からのこの質問を確認してください。

しかし、核となる問題はおそらく未解決のままです。

于 2012-05-28T13:40:38.847 に答える
0

ShiroFilterFactoryBean-and-a-spring-data-mongodb-realmからの具体的な問題の説明:

問題は、spring-data-mongodb を使用する前に、Spring ApplicationEventMulticaster を初期化する必要があることです。

ShiroFilterFactoryBean は beanPostProcessor であるため、初期化中にスプリングはそのレルムを構成しようとします (したがって、私のレルムとスプリング データ mongo ベースの userDao)。ApplicationEventMulticaster がまだ作成されていないため、失敗します。

この問題を解決するためにいくつかの提案された方法を試した後、InitializingBeanApplicationContextAwareまたはBeanPostProcessorインターフェイス (それぞれが時期尚早の呼び出しになるため、必要なサービス/リポジトリのものを初期化する前に) を試した後、次の解決策を思いつきました。

  1. サービス/リポジトリへの自動 Bean 解決なしで、Spring が shiro コンテキストを作成できるようにします。
  2. 春にmongodbを含むサービス/リポジトリコンテキストを作成させます
  3. shiro-service カップリングを処理する単純なクラスを作成し、それに応じて spring 構成で構成します。このクラスは、shiro とサービス コンテキストが正常にセットアップされた後に呼び出されます。

(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-->
/>

(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のものへの追加の負担/依存はありません
  • スプリングの構成とセットアップを完了し、初期化後に一貫した状態にする

不利益:

  • ワンタイムオーバーヘッド設定
  • 接着剤の設定を忘れたりぶつけたりすると、起動時ではなく実行時に不整合な状態になる可能性があります。
于 2013-11-09T12:05:27.390 に答える