1

Spring MVC webapp を保護するために Shiro を使用しています。永続化のために Hibernate を使用しているため、AuthenticationInfo オブジェクトを取得して設定する HibernateRealm があります。

@Override
@Transactional
protected AuthenticationInfo doGetAuthenticationInfo(
        AuthenticationToken token) throws AuthenticationException {
    Account account = accountDao.findByUsername((String)token.getPrincipal());

    SimplePrincipalCollection principals = new SimplePrincipalCollection(account, getName());

    SimpleAccount info = new SimpleAccount(principals, account.getPassword());

    return info;
}

Account私のカスタムユーザークラスです。DAO を使用してAccount、ユーザー名で取得します。この方法を作ることに何か意味があるのだろうかと思っていました@Transactional。結局、これは読み取り専用操作です。

次の問題もあります。DAOはsessionFactory.getCurrentSession()セッションを取得しますが、取得しています

HibernateException: No Session found for current thread 

メソッドが呼び出されたとき。私はアプリケーションコンテキストにこれらを持っています:

<tx:annotation-driven transaction-manager = "transactionManager" />
<bean id="transactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

Spring がセッションを開いてくれない理由がわかりません。

編集:@Controllerログインするには、 Shiro のSpring メソッドを使用してこれを行います。Subject

@RequestMapping(value = "/account/login", method = RequestMethod.POST)
public String login(@RequestParam("username") String username, @RequestParam("password") String password) {
    Subject currentUser = SecurityUtils.getSubject(); 
    if (!currentUser.isAuthenticated) {
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        currentUser.login(token);
        return "profile";
    } 
    return "home";
}

内部的には、Shiro は上記のレルム メソッドを使用して、保存されているユーザー名/パスワード情報を取得します。@AutowiredDAO を使用して、正しいアカウントのデータベースをチェックします。次に、パスワードをCredentialsMatcher実装と照合します。

4

3 に答える 3

2

Spring が Realm Bean のトランザクション プロキシを作成していないようです。これが、Hibernate セッションが使用できない理由を私が理解できる唯一の理由です。バッキング インフラストラクチャが (スレッド上に) 使用できる状態にないためです。

あなたの質問に関しては、それをマークしたい場合は@Transactional、指定することを検討してください@Transactional(readOnly=true)

于 2013-01-21T17:17:37.743 に答える
2

したがって、2 つの問題があります。これらの問題は実際には相互に関連していないため、通常、そのような質問を 2 つに分割することをお勧めします。

  1. 現在のスレッドのセッションが見つかりません@Transactional注釈が機能していないようです。コードまたはテストをデバッグ モードで実行し、スタック内で JdkDynamicAopProxy または同様のものを探すことができることを確認するために、存在する場合は、レルムがトランザクションをインターセプトするプロキシを介して呼び出されますが、現在プロキシはないと思います. それが機能するには、HibernateRealm から直接取得するのではなく、このレルムが実装しているインターフェースを SpringContext から取得する必要があります。これは、組み込みの標準 Java ライブラリ プロキシがインターフェイスしか処理できないためです。
  2. 読み取り専用サービス メソッドをトランザクション対応にすることについて。そうする正当な理由がいくつかあります。
    • Hibernate を使用しているため、実際には複数のクエリを使用して Account オブジェクトを取得する可能性があります。また、このアカウントが同時に変更されると、一貫性のない状態になる可能性があります。
      • アカウント取得の最初のクエリ
      • アカウントが変更または削除された
      • アカウント取得のための 2 番目のクエリ - このクエリは、最初のクエリの結果と一緒に一貫性のない動作につながる可能性のある変更の結果を表示しますが、最初と 2 番目のクエリが適切なレベルのトランザクション分離で同じトランザクションにあった場合、2 番目のクエリは次のようになります。変更が表示されません。
    • データベースへの均一なアクセス - すべてのデータベース接続レイヤーが同じ方法で DB にアクセスすると非常に便利です - アプリケーションの保守と拡張が大幅に簡素化されます。
    • のようないくつかのトランザクションのヒントを使用する@Transactional(readOnly=true)と、適切な構成でパフォーマンスが向上する場合があります (たとえば、非常に負荷の高いアプリケーションの readOnly クエリでは、DB サーバーのセカンダリ レプリカを使用する場合があります)。Spring トランザクションの一部としてメソッドをセットアップするjava.sql.Connection.setReadOnly()方が、他の方法よりもはるかに簡単です。
于 2013-01-21T08:57:26.040 に答える
0

Shiro は自分の Realm の独自のインスタンスを作成するため、Spring にはそれをプロキシでラップする権限がありません。そのため、トランザクション動作を追加できません。

于 2013-01-25T15:57:52.200 に答える