Używam Spring do zarządzania IOC i transakcji i planuję użyć Apache Shiro jako biblioteki bezpieczeństwa.Wiosna ignoruje @ Adransakcyjne adnotacje w klasie Apache Shiro Realm
Za każdym razem, gdy chcę sprawdzić uprawnienia użytkownika, dzwonię pod numer subject.isPermitted("right")
, po czym Shiro sprawdza, czy jest to uprawnienie, korzystając z bazy danych. W ramach tych wywołań nawiązano połączenie z bazą danych, a ja opatrzyłem tę metodę annotacją za pomocą @Transactional
. Zawsze jednak pojawia się błąd, że sesja Hibernate nie jest powiązana z wątkiem za każdym razem, gdy wykonuję kontrolę uprawnień.
Metoda znajduje się w klasie Realm. I zdefiniowano niestandardowy Shiro klasę 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 wykorzystuje filtr serwletu, więc mam następujący zdefiniowane w 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>
Używam programową konfigurację na wiosnę. Oto moja klasa 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;
}
}
Podsumowując kwestię uważam, moja klasa MainRealm jest prawidłowo podłączony (to ma @Autowired zależność do obiektu DAO i sprawdzeniu, że nie jest null) z wyjątkiem adnotacji @Transactional. Z tego powodu nie mogę bezpośrednio wywołać user.isPermitted("")
, ponieważ monituje o błąd: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
.
Chciałbyś poprosić o pomoc w sprawdzeniu, czy czegoś nie przeoczyłem w konfiguracji wiosennej.
W międzyczasie zhakowałem ten problem, wywołując funkcję user.isPermitted("")
w ramach metody w mojej klasie usług, która jest poprawnie związana z @Transactional.
EDIT Kiedy sprawdziłem dzienniki Spring inicjalizacji widzę tak:
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)
Według this SO answer Oznacza to MainRealm
nie jest postprocessed przez menedżera transakcji w związku z tym wszelkie @Transactional adnotacje ignorowany. Jeśli tak, jak mogę to poprawić?
EDIT 2 Według this SO question: „Innymi słowy, jeśli piszę własną BeanPostProcessor, a klasa bezpośrednio odwołuje innych ziaren w kontekście, to te przywoływane fasola nie będzie kwalifikował się do auto-proxy, a wiadomość jest rejestrowana w tym celu. " Właśnie sprawdziłem ShiroFilterFactoryBean
i jest to w rzeczywistości proces BeanPostProcessor. Problem polega na tym, że wymaga instancji SecurityManager
, która z kolei wymaga instancji MainRealm
. Tak więc obydwie fasole są autowyredowane i dlatego nie kwalifikują się do proxy. Czuję, że jestem bliżej rozwiązania, ale nadal nie mogę go rozwiązać.
Można spróbować przenieść wszystkie logiki transakcyjnej w pewnym 'UserService' z' @ Transactional' lub '@Transactional (tylko do odczytu = true)' adnotacji i skorzystać z tej usługi w swoim 'MainRealm'. – sody
Próbowałem wyposażyć klasę usług w moją dziedzinę, jednak w tym przypadku klasa usługi napotkała również błąd "Brak sesji hibernacji związanej z wątkiem", a adnotacje @Transactional nie działały. Wygląda na to, że robię coś złego podczas inicjowania obiektów Shiro. –