简体   繁体   English

Shiro Authenticating Realm应该是交易吗?

[英]Should a Shiro Authenticating Realm be transactional?

I'm using Shiro to secure my Spring MVC webapp. 我正在使用Shiro来保护我的Spring MVC webapp。 I'm using Hibernate for persistence and so I have a HibernateRealm to get and populate an AuthenticationInfo object. 我正在使用Hibernate进行持久化,因此我有一个HibernateRealm来获取并填充AuthenticationInfo对象。

@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 is my custom user class. Account是我的自定义用户类。 I use the DAO to retrieve an Account by username. 我使用DAO通过用户名检索Account I was wondering if there is any point in making this method @Transactional . 我想知道这个方法@Transactional是否有任何意义。 This is a read only operation after all. 毕竟这是一个只读操作。

I'm also having the following problem: the DAO does sessionFactory.getCurrentSession() to get a session, but I'm getting a 我也有以下问题:DAO执行sessionFactory.getCurrentSession()来获取会话,但我得到了一个

HibernateException: No Session found for current thread 

when the method gets called. 当方法被调用时。 I have these in my application context: 我在我的应用程序上下文中有这些:

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

I can't understand why Spring isn't opening a session for me. 我无法理解为什么Spring没有为我开会。

Edit: To login, we do this in a Spring @Controller method using Shiro's Subject 编辑:要登录,我们使用Shiro的Subject在Spring @Controller方法中执行此操作

@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";
}

Internally, Shiro uses the realm method I have above to get the stored username/password information. 在内部,Shiro使用我上面的领域方法来获取存储的用户名/密码信息。 It uses an @Autowired DAO to check my database for the right account. 它使用@Autowired DAO检查我的数据库是否有正确的帐户。 It then matches the passwords with a CredentialsMatcher implementation. 然后,它将密码与CredentialsMatcher实现进行匹配。

So you have two problems. 所以你有两个问题。 It is usually better to split such questions into two, since these problems are not really connected to each other. 通常最好将这些问题分成两部分,因为这些问题并没有真正相互联系。

  1. No Session found for current thread It seems that @Transactional annotations does not work. 找不到当前线程的会话似乎@Transactional注释不起作用。 To be sure you may run you code or tests in Debug mode and look for the JdkDynamicAopProxy or something similar in the stack - if it is present, than your Realm is invoked through transactions-intercepting proxy, but I suppose that there is no proxy curently. 为了确保你可以在调试模式下运行你的代码或测试并在堆栈中查找JdkDynamicAopProxy或类似的东西 - 如果它存在,那么你的Realm是通过事务拦截代理调用的,但我想没有代理功能。 For it to work you need to take from the SpringContext not the HibernateRealm directly but the interface that this realm is implementing. 要使它工作,您需要从SpringContext而不是直接从HibernateRealm获取,但是这个领域正在实现的接口。 This is due to the fact that built-in standard java library proxies can deal only with interfaces. 这是因为内置的标准java库代理只能处理接口。
  2. As for making the read-only service methods transactional. 至于使只读服务方法具有事务性。 There are several valid reasons to do so: 有几个正当理由这样做:
    • Since you are using Hibernate it is really possible that you actually use more than one query to get your Account object. 由于您使用的是Hibernate,因此您实际上可能会使用多个查询来获取您的Account对象。 And if this account is modified concurrently it may lead to inconsistent state: 如果同时修改此帐户,可能会导致状态不一致:
      • first query for Account retrieval 首先查询帐户检索
      • Account is modified or deleted 帐户被修改或删除
      • second query for Account retrieval - this query will see the results of modification that together with the results of the first query may lead to inconsistent behavior, but if first and second query were in the same transaction with the proper level of transaction isolation second query would not see the modifications. 第二个查询用于帐户检索 - 此查询将看到修改结果与第一个查询的结果一起可能导致不一致的行为,但如果第一个和第二个查询在同一事务中具有适当级别的事务隔离第二个查询将没有看到修改。
    • Uniform access to the database - it is really helpful when all your database connectivity layer access the DB in one and the same way - I greatly simplifies maintaining and extending of the application. 统一访问数据库 - 当所有数据库连接层以同样的方式访问数据库时,它非常有用 - 我极大地简化了应用程序的维护和扩展。
    • Using some transactional hints like @Transactional(readOnly=true) may improve your performance with proper configuration (eg for the really high-loaded application readOnly queries may use secondary replica of the DB Server). 使用某些事务提示(如@Transactional(readOnly=true)可以通过正确配置提高性能(例如,对于真正高负载的应用程序,readOnly查询可能使用数据库服务器的辅助副本)。 It is really easier to setup the java.sql.Connection.setReadOnly() method as part of the Spring transactions, than in the other way. java.sql.Connection.setReadOnly()方法设置为Spring事务的一部分比在其他方面更容易。

It appears that Spring isn't creating a transactional proxy for your Realm bean. 看来Spring并没有为你的Realm bean创建一个事务代理。 This is the only reason that I can see why a Hibernate Session isn't available - because the backing infrastructure isn't there (on the thread) ready for use. 这是我可以理解为什么Hibernate会话不可用的唯一原因 - 因为支持基础设施不存在(在线程上)可供使用。

As to your question, if you do want to mark it @Transactional , you might consider specifying @Transactional(readOnly=true) 至于你的问题,如果你想将它标记为@Transactional ,你可以考虑指定@Transactional(readOnly=true)

Shiro creates it's own instance of my Realm and therefore Spring has no power over it to wrap it in a proxy. Shiro创建了它自己的Realm实例,因此Spring没有权力将它包装在代理中。 That's why it can't add the transactional behavior. 这就是为什么它无法添加事务行为。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM