Shiro Authenticating Realm应该是交易吗?

时间:2013-01-20 17:35:17

标签: java hibernate spring-mvc shiro

我正在使用Shiro来保护我的Spring MVC webapp。我正在使用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是我的自定义用户类。我使用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没有为我开会。

修改要登录,我们使用Shiro的@Controller

在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使用我上面的领域方法来获取存储的用户名/密码信息。它使用@Autowired DAO检查我的数据库中是否有正确的帐户。然后,它将密码与CredentialsMatcher实施匹配。

3 个答案:

答案 0 :(得分:2)

所以你有两个问题。通常最好将这些问题分成两部分,因为这些问题并没有真正相互联系。

  1. 找不到当前主题的会话 似乎@Transactional注释不起作用。为了确保你可以在调试模式下运行你的代码或测试并在堆栈中查找JdkDynamicAopProxy或类似的东西 - 如果它存在,那么你的Realm是通过事务拦截代理调用的,但我想没有代理功能。要使它工作,您需要从SpringContext而不是直接从HibernateRealm获取,但是这个领域正在实现的接口。这是因为内置的标准java库代理只能处理接口。
  2. 至于使只读服务方法具有事务性。 有几个正当理由这样做:
    • 由于您正在使用Hibernate,因此您实际上可能会使用多个查询来获取您的Account对象。如果同时修改此帐户,可能会导致状态不一致:
      • 首次查询帐户检索
      • 修改或删除帐户
      • 对帐户检索的第二个查询 - 此查询将看到修改结果与第一个查询的结果一起可能导致不一致的行为,但是如果第一个和第二个查询在同一事务中具有适当的事务隔离级别第二个查询不会看到修改。
    • 统一访问数据库 - 当所有数据库连接层以同样的方式访问数据库时,它非常有用 - 我极大地简化了应用程序的维护和扩展。
    • 使用某些事务提示(如@Transactional(readOnly=true))可以通过正确配置提高性能(例如,对于真正高负载的应用程序,readOnly查询可能使用数据库服务器的辅助副本)。作为Spring事务的一部分,将java.sql.Connection.setReadOnly()方法设置为比其他方式更容易。

答案 1 :(得分:2)

看来Spring没有为你的Realm bean创建一个事务代理。这是我可以理解为什么Hibernate会话不可用的唯一原因 - 因为支持基础设施不在那里(在线程上)可以使用。

关于您的问题,如果您想标记@Transactional,可以考虑指定@Transactional(readOnly=true)

答案 2 :(得分:0)

Shiro创建了它自己的Realm实例,因此Spring没有权力将它包装在代理中。这就是为什么它无法添加交易行为。