Jen*_*ing 6 spring hibernate shiro
我正在使用Spring进行IOC和事务管理,并计划使用Apache Shiro作为安全库.
每当我想检查用户的权限时,我都会打电话subject.isPermitted("right"),然后Shiro使用数据存储区检查权限.在这些调用中,建立了数据库连接,并且我已使用注释方法@Transactional.但是,每当我执行权限检查时,总是会收到一个错误,即没有Hibernate会话绑定到该线程.
该方法在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;
}
}
Run Code Online (Sandbox Code Playgroud)
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>
Run Code Online (Sandbox Code Playgroud)
我正在使用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;
}
}
Run Code Online (Sandbox Code Playgroud)
总结一下这个问题,我相信我的MainRealm类正在正确连接(它有一个@Autowired依赖于DAO对象,我验证它不是null),但@Transactional注释除外.因此,我无法直接调用,user.isPermitted("")因为它会提示错误:No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here.
想请求帮助检查我的Spring配置中是否遗漏了任何内容.
与此同时,我通过user.isPermitted("")在我的Service类中的一个方法中调用函数来解决这个问题,该方法被@Transactional正确绑定.
编辑当我检查日志的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)
Run Code Online (Sandbox Code Playgroud)
根据这个SO答案,它意味着MainRealm事务管理器没有对其进行后处理,因此任何@Transactional注释都会被忽略.如果是这样,我该如何纠正?
编辑2根据这个问题:"换句话说,如果我编写自己的BeanPostProcessor,并且该类直接引用上下文中的其他bean,那么这些引用的bean将不符合自动代理的条件,并且会记录一条消息那种效果." 我刚检查过ShiroFilterFactoryBean,它实际上是一个BeanPostProcessor.问题是它需要一个SecurityManager实例,而实例又需要一个MainRealm实例.因此两个bean都是自动装配的,因此没有资格进行代理.我觉得我更接近解决方案,但我仍然无法解决它.
实际上,此问题的根本原因是由于以下原因:
所有BeanPostProcessor及其直接引用的bean都将在启动时实例化...由于AOP自动代理是作为BeanPostProcessor本身实现的,因此没有BeanPostProcessor或直接引用的bean都可以进行自动代理(因此不会“编织”到他们。
引用的SO问题在这里。
我已经通过将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;
}
Run Code Online (Sandbox Code Playgroud)
改为以下代码:
@Bean
public DefaultWebSecurityManager securityManager() {
final DefaultWebSecurityManager sm = new DefaultWebSecurityManager();
//sm.setRealm(mainRealm); -> set this AFTER Spring initialization so no dependencies
return sm;
}
Run Code Online (Sandbox Code Playgroud)
然后,我使用ServletContextListener侦听Spring上下文初始化完成时的响应,并且同时拥有MainRealm和SecurityManagerbean。然后,我只是将一个豆插入另一个豆中。
@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);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1482 次 |
| 最近记录: |