shiro配置 AOP式方法级权限检查时 事务失效

发布于 2021-12-02 13:11:58 字数 2503 浏览 992 评论 8

当对shiro配置 AOP式方法级权限检查时:

<!-- AOP式方法级权限检查  -->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
        <property name="proxyTargetClass" value="true" />
    </bean>
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>

执行删除操作时(删除用户,同时删除用户下的任务)会报错:

Caused by: javax.persistence.TransactionRequiredException: Executing an update/delete query
 at org.hibernate.ejb.AbstractQueryImpl.executeUpdate(AbstractQueryImpl.java:96)
 at org.springframework.data.jpa.repository.query.JpaQueryExecution$ModifyingExecution.doExecute(JpaQueryExecution.java:154)
 at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:55)
 at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:95)
 at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:85)
 at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:313)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
 at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
 at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155)

具体错误语句,我测试过应该是:

taskDao.deleteByUserId(id);
@Modifying
@Query("delete from Task task where task.user.id = :id")
void deleteByUserId(@Param("id") Long id);
 

如果修改为:taskDao.delete(id); delete(id)是JPA DATA中的方法,不会报错。

不配置AOP式方法级权限检查,也不会报错。

在quickstart和showcase都会存在,配置方法和showcase一模一样,showcase虽然有这个例子,也不会报错,但可惜这种情况,属于我的上面举的不报错的情况,调用的是JPA自带的delete方法。希望作者能看一下,看看是什么问题,也希望大家能解决一下。经过我测试,是不是JPA DATA 和 shior AOP式方法级权限检查有冲突,导致事务失效!!!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

你曾走过我的故事 2021-12-06 14:01:20

引用来自“飘渺青衣”的评论

realm先不注入securityManager里,然后我写了一个事件,然后事物好用了

@Component

public class ShiroInitListener implements ApplicationListener<ContextRefreshedEvent> {

@Autowired

private Collection<Realm> realms;

@Resource

private RealmSecurityManager securityManager;

/* (non-Javadoc)

*
@see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)

*/

@Override

public void onApplicationEvent(ContextRefreshedEvent arg0) {

if(this.realms != null && this.securityManager != null) {

securityManager.setRealms(realms);

}

}

}

谢绝鈎搭 2021-12-06 13:53:02

realm先不注入securityManager里,然后我写了一个事件,然后事物好用了

@Component

public class ShiroInitListener implements ApplicationListener<ContextRefreshedEvent> {

@Autowired

private Collection<Realm> realms;

@Resource

private RealmSecurityManager securityManager;

/* (non-Javadoc)

*
@see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)

*/

@Override

public void onApplicationEvent(ContextRefreshedEvent arg0) {

if(this.realms != null && this.securityManager != null) {

securityManager.setRealms(realms);

}

}

}

哑剧 2021-12-06 13:43:43

意思就是在spring-shiro.xml中不配置realm,而是在spring监听完成后把realm设置到securityManager。

野心澎湃 2021-12-06 13:39:00

求解啊 。。。。

樱花落人离去 2021-12-06 12:52:02

The root cause of the issue is in fact due to the following:

All BeanPostProcessors and their directly referenced beans will be instantiated on startup... Since AOP auto-proxying is implemented as a BeanPostProcessor itself, no BeanPostProcessors or directly referenced beans are eligible for auto-proxying (and thus will not have aspects 'woven' into them.

Referenced SO question is here.

I have resolved this issue by decoupling the Realm bean creation from the SecurityManager bean creation.

The relevant change is from the following code:

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

to the following code:

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

Then I use a ServletContextListener which listens to when the Spring context initialization completes and I have the both the MainRealm and SecurityManager beans. Then I just plug one bean inside another.

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

没太看懂怎么解决

拍不死你 2021-12-06 09:00:47

现在肯定的是与shiro有关

睫毛上残留的泪 2021-12-06 08:40:03

我也遇到了这个问题,不知道楼主有没有解决?

回眸一笑 2021-12-03 18:50:18

自己顶

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文