org.hibernate.HibernateException: No session currently bound to execution context
I'm trying to integrate Spring Security with Hibernate. I'm new to both technologies so I'm almost certainly taking too many steps at once here, but I'm at the point where I want to authenticate a user from the database. I think this is certainly more a Hibernate problem that a Spring Security one but I mention it to give some context. Below is the error message and the code. Can anyone spot something?
org.hibernate.HibernateException: No session currently bound to execution context
org.hibernate.context.ManagedSessionContext.currentSession(ManagedSessionContext.java:74)
org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:622)
com.vicinity.dao.hibernate.GenericHibernateDAO.findByCriteria(GenericHibernateDAO.java:99)
com.vicinity.dao.hibernate.HibernateUserDAO.getUserByLogin(HibernateUserDAO.java:35)
com.vicinity.service.PersistentUserManager.loadUserByUsername(PersistentUserManager.java:67)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
java.lang.reflect.Method.invoke(Unknown Source)
org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:307)
org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:107)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
$Proxy31.loadUserByUsername(Unknown Source)
org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:83)
org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:125)
org.springframework.security.authentication.ProviderManager.doAuthentication(ProviderManager.java:121)
org.springframework.security.authentication.AbstractAuthenticationManager.authenticate(AbstractAuthenticationManager.java:49)
org.springframework.security.authentication.ProviderManager.doAuthentication(ProviderManager.java:139)
org.springframework.security.authentication.AbstractAuthenticationManager.authenticate(AbstractAuthenticationManager.java:49)
org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:98)
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:356)
org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:106)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:356)
org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:356)
org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.jav开发者_开发问答a:108)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:356)
org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:150)
org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
Configuration of the DAO and transaction management:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="hibernateUserDAO" class="com.vicinity.dao.hibernate.HibernateUserDAO">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="userManagerTarget" class="com.vicinity.service.PersistentUserManager">
<property name="userDAO" ref="hibernateUserDAO" />
</bean>
<bean id="userManager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref local="transactionManager" />
</property>
<property name="target">
<ref local="userManagerTarget" />
</property>
<property name="transactionAttributes">
<props>
<prop key="loadUserByUsername">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
Here is the class that implements the UserDetailsService
which is called to authenticate the user. This makes a call to the DAO, see the line userDAO.getUserByLogin(login);
:
@Service("userManager")
@Transactional(propagation = Propagation.REQUIRED, readOnly = true)
public class PersistentUserManager implements UserManager, UserDetailsService {
@Override
public UserDetails loadUserByUsername(String login) throws UsernameNotFoundException, DataAccessException {
User user = userDAO.getUserByLogin(login);
if (null == user) {
logger.error("User with login: " + login + " not found in database");
throw new UsernameNotFoundException("user not found in database");
}
org.springframework.security.core.userdetails.User springUser;
springUser = new org.springframework.security.core.userdetails.User(user.getLogin(), user.getPassword(), true,
true, true, true, new ArrayList<GrantedAuthority>());
return springUser;
}
}
Here is the DAO which reads from the database. Note that I'm trying to take advantage of the 'GenericDAO pattern':
@Repository("userDAO")
public class HibernateUserDAO extends GenericHibernateDAO<User, Long> implements UserDAO {
public HibernateUserDAO() {
super(User.class);
}
@Override
public void createUser(User user) {
super.makePersistent(user);
}
public User getUserByLogin(String login) {
if (null == login) {
throw new IllegalArgumentException("You must provide a username if you want to get the user.");
}
List<User> users = findByCriteria(Restrictions.eq("login", login));
// TODO, might need to check here if there are more than one user with the same username
if(users == null || users.size() == 0) {
return null;
} else {
return users.get(0);
}
}
}
Here's the class where the error occurs, the line Criteria crit = getSessionFactory().getCurrentSession().createCriteria(getPersistentClass());
:
public abstract class GenericHibernateDAO<T, ID extends Serializable> implements GenericDAO<T, ID> {
private Class<T> persistentClass;
private SessionFactory sessionFactory;
@SuppressWarnings("unchecked")
protected List<T> findByCriteria(Criterion... criterion) {
Criteria crit = getSessionFactory().getCurrentSession().createCriteria(getPersistentClass());
for (Criterion c : criterion) {
crit.add(c);
}
return crit.list();
}
}
I have the following in my hibernate configuration (hibernate.cfg.xml) which may be relavent:
<property name="current_session_context_class">org.hibernate.context.ManagedSessionContext</property>
Try with this property name.
<property name="hibernate.current_session_context_class">
org.hibernate.context.ManagedSessionContext</property>
However, it is preferable that you configure spring to be in charge of your session and transaction management. You can check this.
Have you configured transaction management?
org.springframework.orm.hibernate3.HibernateTransactionManager
and
org.springframework.transaction.interceptor.TransactionProxyFactoryBean
I recently ran into the exact same sort of error, and beat my head against the wall trying to figure out what the problem was.
In my case, I was using the OpenSessionInViewFilter
configured in the web.xml
file, along with the Spring Security configuration there as well.
Since both Spring Security and OpenSessionInViewFilter
are filters, the order in which they are applied depends on the order they appear in the web.xml
file.
In my case, I initially had the OpenSessionInViewFilter
below the Spring Security filter. Once I swapped their positions (ie. put the OpenSessionInViewFilter
above the Spring Security one), everything worked just fine!
I think the problem is coming due to
springUser = new org.springframework.security.core.userdetails.User(user.getLogin(), user.getPassword(), true, true, true, true, new ArrayList<GrantedAuthority>());
Spring uses a Template pattern in the DAO, so when you do getUserByLogin
a session is created by Spring and when you come out of this method the session is closed.So when you do user.getLogin()
again there is no session attached and you get the error.
Try to use OpenSessionInViewFilter
.... you might have to search in google for it (as i have also not used it myself, hence cannot show code here)
Also you can do one more thing, if you return the springUser
from the DAO itself (i.e in getUserByLogin
itself, then it will use the same session object and it should work)
精彩评论