gpt4 book ai didi

Spring 忽略了 Apache Shiro Realm 类中的 @Transactional 注释

转载 作者:行者123 更新时间:2023-12-04 14:46:43 42 4
gpt4 key购买 nike

我正在使用 Spring 进行 IOC 和事务管理,并计划使用 Apache Shiro 作为安全库。

每当我想检查用户的权限时,我都会调用 subject.isPermitted("right") ,于是 Shiro 使用数据存储检查权限。在这些调用中,建立了一个数据库连接,并且我用 @Transactional 注释了该方法。 .但是,每当我执行权限检查时,我总是收到一个错误,即没有绑定(bind)到线程的 Hibernate session 。

该方法在 Realm 类中。我定义了一个自定义 Shiro Realm 类:

@Component
public class MainRealm extends AuthorizingRealm {

@Autowired
protected SysUserDao userDao;

@Transactional
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
throws AuthenticationException {
...
final SysUser user = this.userDao.findByUsername(un);
...
return authInfo;
}

@Transactional
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
...
permissions = this.userDao.getAccessRights(un);
...
return authInfo;
}
}

Apache Shiro 使用 Servlet 过滤器,所以我在 web.xml 中定义了以下内容:
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>

我正在为 Spring 使用编程配置。这是我的 App Config 类:
@Configuration //Replaces Spring XML configuration
@ComponentScan(basePackages = "com.mycompany")
@EnableTransactionManagement //Enables declarative Transaction annotations
public class SpringAppConfig {

@Bean
public DataSource sqlServerDataSource() throws Exception {...}
@Bean
@Autowired
public PlatformTransactionManager transactionManager(SessionFactory sessionFactory) {...}
@Bean
public AnnotationSessionFactoryBean getSessionFactory() throws Exception {...}
@Bean
public static PersistenceExceptionTranslationPostProcessor exceptionTranslation() {...}

@Bean
@Autowired
public DefaultWebSecurityManager securityManager(MainRealm mainRealm) {
final HashedCredentialsMatcher hcm = new HashedCredentialsMatcher(shiroHash);
hcm.setHashIterations(shiroIter);
hcm.setStoredCredentialsHexEncoded(shiroHexEncoded);
mainRealm.setCredentialsMatcher(hcm);
final DefaultWebSecurityManager sm = new DefaultWebSecurityManager();
sm.setRealm(mainRealm);
return sm;
}

@Bean
@Autowired
public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) {
final ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean();
filter.setSecurityManager(securityManager);
return filter;
}

/**
* This method needs to be static due to issues defined here:<br>
* https://issues.apache.org/jira/browse/SHIRO-222
*/
@Bean
public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
LifecycleBeanPostProcessor lbpp = new LifecycleBeanPostProcessor();
return lbpp;
}

@Bean
@DependsOn("lifecycleBeanPostProcessor")
public static DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
return new DefaultAdvisorAutoProxyCreator();
}

@Bean
@Autowired
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager secMan) {
AuthorizationAttributeSourceAdvisor advBean = new AuthorizationAttributeSourceAdvisor();
advBean.setSecurityManager(secMan);
return advBean;
}
}

总结一下这个问题,我相信我的 MainRealm 类连接正确(它有一个对 DAO 对象的 @Autowired 依赖项,我验证它不为空),但 @Transactional 注释除外。因此,我无法直接调用 user.isPermitted("")因为它提示错误: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here .

想寻求帮助以检查我是否错过了 Spring 配置中的任何内容。

与此同时,我通过调用 user.isPermitted("") 解决了这个问题。在我的服务类中由@Transactional 正确绑定(bind)的方法中的函数。

编辑 当我检查 Spring 初始化的日志时,我可以看到:
Bean 'mainRealm' of type [class com.x.security.MainRealm] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)

根据 this SO answer这意味着 MainRealm事务管理器没有进行后处理,因此任何 @Transactional 注释都会被忽略。如果是这样,我该如何纠正?

编辑 2 根据 this SO question :“换句话说,如果我编写自己的 BeanPostProcessor,并且该类直接引用上下文中的其他 bean,那么那些引用的 bean 将不符合自动代理的条件,并且会记录一条消息以达到该效果。”我刚刚检查了 ShiroFilterFactoryBean它实际上是一个 BeanPostProcessor。问题是它需要 SecurityManager反过来需要 MainRealm 的实例实例。所以这两个 bean 都是 Autowiring 的,因此没有资格进行代理。我觉得我更接近解决方案,但我仍然无法解决它。

最佳答案

问题的根本原因实际上是由于以下几点:

所有 BeanPostProcessor 及其直接引用的 bean 都将在启动时实例化...由于 AOP 自动代理是作为 BeanPostProcessor 本身实现的,因此没有 BeanPostProcessor 或直接引用的 bean 有资格进行自动代理(因此不会将方面“编织”到他们。

引用的 SO 问题是 here .

我通过将 Realm bean 创建与 SecurityManager bean 创建解耦解决了这个问题。

相关更改来自以下代码:

@Bean
@Autowired
public DefaultWebSecurityManager securityManager(MainRealm mainRealm) {
final HashedCredentialsMatcher hcm = new HashedCredentialsMatcher(shiroHash);
hcm.setHashIterations(shiroIter);
hcm.setStoredCredentialsHexEncoded(shiroHexEncoded);
mainRealm.setCredentialsMatcher(hcm);
final DefaultWebSecurityManager sm = new DefaultWebSecurityManager();
sm.setRealm(mainRealm);
return sm;
}

到以下代码:
@Bean
public DefaultWebSecurityManager securityManager() {
final DefaultWebSecurityManager sm = new DefaultWebSecurityManager();
//sm.setRealm(mainRealm); -> set this AFTER Spring initialization so no dependencies
return sm;
}

然后我使用 ServletContextListener 来监听 Spring 上下文初始化完成的时间,并且我同时拥有 MainRealmSecurityManager bean 。然后我只是把一个 bean 塞进另一个 bean 里。
@Override
public void contextInitialized(ServletContextEvent sce) {
try {

//Initialize realms
final MainRealm mainRealm = (MainRealm)ctx.getBean("mainRealm");
final DefaultWebSecurityManager sm = (DefaultWebSecurityManager)ctx.getBean("securityManager");
sm.setRealm(mainRealm);
} catch (Exception e) {
System.out.println("Error loading: " + e.getMessage());
throw new Error("Critical system error", e);
}
}

关于Spring 忽略了 Apache Shiro Realm 类中的 @Transactional 注释,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15922559/

42 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com