Main Tutorials

Spring Security + Hibernate Annotation Example

spring-hibernate-logo

In this tutorial, previous Spring Security + Hibernate4 XML example will be reused, and convert it to a annotation-based example.

Technologies used :

  1. Spring 3.2.8.RELEASE
  2. Spring Security 3.2.3.RELEASE
  3. Hibernate 4.2.11.Final
  4. MySQL Server 5.6
  5. Tomcat 7 (Servlet 3.x container)

Quick Note :

  1. Create a session factory with LocalSessionFactoryBuilder
  2. Inject session factory into a UserDao
  3. Integrate UserDao into a custom UserDetailsService, to load users from the database.

1. Project Directory

A final project directory structure.

spring-security-hibernate-annotation-directory

2. User Model + Mapping File

Model classes and its’ annotation-based mapping file.

User.java

package com.mkyong.users.model;

import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "users", catalog = "test")
public class User {

	private String username;
	private String password;
	private boolean enabled;
	private Set<UserRole> userRole = new HashSet<UserRole>(0);

	public User() {
	}

	public User(String username, String password, boolean enabled) {
		this.username = username;
		this.password = password;
		this.enabled = enabled;
	}

	public User(String username, String password, 
		boolean enabled, Set<UserRole> userRole) {
		this.username = username;
		this.password = password;
		this.enabled = enabled;
		this.userRole = userRole;
	}

	@Id
	@Column(name = "username", unique = true, 
		nullable = false, length = 45)
	public String getUsername() {
		return this.username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	@Column(name = "password", 
		nullable = false, length = 60)
	public String getPassword() {
		return this.password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	@Column(name = "enabled", nullable = false)
	public boolean isEnabled() {
		return this.enabled;
	}

	public void setEnabled(boolean enabled) {
		this.enabled = enabled;
	}

	@OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
	public Set<UserRole> getUserRole() {
		return this.userRole;
	}

	public void setUserRole(Set<UserRole> userRole) {
		this.userRole = userRole;
	}

}
UserRole.java

package com.mkyong.users.model;

import static javax.persistence.GenerationType.IDENTITY;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;

@Entity
@Table(name = "user_roles", catalog = "test", 
	uniqueConstraints = @UniqueConstraint(
		columnNames = { "role", "username" }))
public class UserRole{

	private Integer userRoleId;
	private User user;
	private String role;

	public UserRole() {
	}

	public UserRole(User user, String role) {
		this.user = user;
		this.role = role;
	}

	@Id
	@GeneratedValue(strategy = IDENTITY)
	@Column(name = "user_role_id", 
		unique = true, nullable = false)
	public Integer getUserRoleId() {
		return this.userRoleId;
	}

	public void setUserRoleId(Integer userRoleId) {
		this.userRoleId = userRoleId;
	}

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "username", nullable = false)
	public User getUser() {
		return this.user;
	}

	public void setUser(User user) {
		this.user = user;
	}

	@Column(name = "role", nullable = false, length = 45)
	public String getRole() {
		return this.role;
	}

	public void setRole(String role) {
		this.role = role;
	}

}

3. DAO Class

DAO classes, to load data from the database, via Hibernate.

UserDao.java

package com.mkyong.users.dao;

import com.mkyong.users.model.User;

public interface UserDao {

	User findByUserName(String username);

}
UserDaoImpl.java

package com.mkyong.users.dao;

import java.util.ArrayList;
import java.util.List;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.mkyong.users.model.User;

@Repository
public class UserDaoImpl implements UserDao {

	@Autowired
	private SessionFactory sessionFactory;

	@SuppressWarnings("unchecked")
	public User findByUserName(String username) {

		List<User> users = new ArrayList<User>();

		users = sessionFactory.getCurrentSession()
			.createQuery("from User where username=?")
			.setParameter(0, username)
			.list();

		if (users.size() > 0) {
			return users.get(0);
		} else {
			return null;
		}

	}

}

4. UserDetailsService

Uses @Transactional to declare a transactional method.

MyUserDetailsService.java

package com.mkyong.users.service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.mkyong.users.dao.UserDao;
import com.mkyong.users.model.UserRole;

@Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {

	//get user from the database, via Hibernate
	@Autowired
	private UserDao userDao;

	@Transactional(readOnly=true)
	@Override
	public UserDetails loadUserByUsername(final String username) 
		throws UsernameNotFoundException {
	
		com.mkyong.users.model.User user = userDao.findByUserName(username);
		List<GrantedAuthority> authorities = 
                                      buildUserAuthority(user.getUserRole());

		return buildUserForAuthentication(user, authorities);
		
	}

	// Converts com.mkyong.users.model.User user to
	// org.springframework.security.core.userdetails.User
	private User buildUserForAuthentication(com.mkyong.users.model.User user, 
		List<GrantedAuthority> authorities) {
		return new User(user.getUsername(), user.getPassword(), 
			user.isEnabled(), true, true, true, authorities);
	}

	private List<GrantedAuthority> buildUserAuthority(Set<UserRole> userRoles) {

		Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();

		// Build user's authorities
		for (UserRole userRole : userRoles) {
			setAuths.add(new SimpleGrantedAuthority(userRole.getRole()));
		}

		List<GrantedAuthority> Result = new ArrayList<GrantedAuthority>(setAuths);

		return Result;
	}

}

5. Spring Security Annotation

Declares and binds everything with annotations, read the comments, it should be self-explanatory.

SecurityConfig.java

package com.mkyong.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	@Qualifier("userDetailsService")
	UserDetailsService userDetailsService;

	@Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {

	    http.authorizeRequests().antMatchers("/admin/**")
		.access("hasRole('ROLE_ADMIN')").and().formLogin()
		.loginPage("/login").failureUrl("/login?error")
		.usernameParameter("username")
		.passwordParameter("password")
		.and().logout().logoutSuccessUrl("/login?logout")
		.and().csrf()
		.and().exceptionHandling().accessDeniedPage("/403");
	}
	
	@Bean
	public PasswordEncoder passwordEncoder(){
		PasswordEncoder encoder = new BCryptPasswordEncoder();
		return encoder;
	}
	
}

Uses LocalSessionFactoryBuilder to create a session factory.

AppConfig.java

package com.mkyong.config;

import java.util.Properties;
import org.apache.commons.dbcp.BasicDataSource;
import org.hibernate.SessionFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBuilder;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

@EnableWebMvc
@Configuration
@ComponentScan({ "com.mkyong.*" })
@EnableTransactionManagement
@Import({ SecurityConfig.class })
public class AppConfig {

        @Bean
        public SessionFactory sessionFactory() {
                LocalSessionFactoryBuilder builder = 
			new LocalSessionFactoryBuilder(dataSource());
                builder.scanPackages("com.mkyong.users.model")
                      .addProperties(getHibernateProperties());

                return builder.buildSessionFactory();
        }

	private Properties getHibernateProperties() {
                Properties prop = new Properties();
                prop.put("hibernate.format_sql", "true");
                prop.put("hibernate.show_sql", "true");
                prop.put("hibernate.dialect", 
                    "org.hibernate.dialect.MySQL5Dialect");
                return prop;
        }
	
	@Bean(name = "dataSource")
	public BasicDataSource dataSource() {
		
		BasicDataSource ds = new BasicDataSource();
	        ds.setDriverClassName("com.mysql.jdbc.Driver");
		ds.setUrl("jdbc:mysql://localhost:3306/test");
		ds.setUsername("root");
		return ds;
	}
	
	//Create a transaction manager
	@Bean
        public HibernateTransactionManager txManager() {
                return new HibernateTransactionManager(sessionFactory());
        }
		
	@Bean
	public InternalResourceViewResolver viewResolver() {
		InternalResourceViewResolver viewResolver 
                             = new InternalResourceViewResolver();
		viewResolver.setViewClass(JstlView.class);
		viewResolver.setPrefix("/WEB-INF/pages/");
		viewResolver.setSuffix(".jsp");
		return viewResolver;
	}
	
}

Done.

6. Project Demo

The following video demo is for the Spring Security database login tutorial. Since this tutorial is generating the same output, so the video demo is reused.

6.1 Access a password protected page : http://localhost:8080/spring-security-hibernate-annotation/admin , a login page is displayed.

spring-security-hibernate-annotation1

6.2 Enter user “mkyong” and password “123456”.

spring-security-hibernate-annotation2

6.3 Try access /admin page with user “alex” and password “123456”, a 403 page will be displayed.

spring-security-hibernate-annotation3

Download Source Code

References

  1. Spring Security + Hibernate XML Example
  2. Spring Security Hello World Annotation Example
  3. LocalSessionFactoryBuilder JavaDoc
  4. Spring ORM – Hibernate
  5. Spring Hibernate4 LocalSessionFactoryBean JavaDoc
  6. Spring Transaction Management
  7. Hibernate ORM documentation
  8. Spring Security Form Login Using Database, with JDBC
  9. Hibernate : No Session Found For Current Thread

About Author

author image
Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter. If you like my tutorials, consider make a donation to these charities.

Comments

Subscribe
Notify of
52 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
gianluca
9 years ago

but someone has solved the problem of the user name and password always incorrect ?

sora
9 years ago

hi..i try to follow this tutorial but got error..even when i use
downloaded project also got same error..pls help me im new in
spring..thx

Error creating bean with name ‘securityConfig’: Injection of autowired dependencies failed…
Actually it cant autowired to anything..i think perhaps got problem with @Componentscan and i try to specific the package but it still same..thx

Akash Agarwal
8 years ago
Reply to  sora

how did u get rid of this ?

Luis Gomez
4 years ago

It was the only example that worked for me. Thanks a lot.

sunny
5 years ago

damn. code is not working

juveria
5 years ago

no explanation no use

Vamshi Krishna
6 years ago

Hi All, I am new to Spring Security. I have a doubt in MyUserDestailsService implementation. In the following method we are creating a User object with 7 parameters but we don’t have such constructor defined. How it is possible? If possible how it will happen and what are the other boolean parameters. Please let me know.
private User buildUserForAuthentication(com.mkyong.users.model.User user,
List authorities) {
return new User(user.getUsername(), user.getPassword(),
user.isEnabled(), true, true, true, authorities);
}

Thanks,
Vamshi

JDH
4 years ago
Reply to  Vamshi Krishna

Because this User object is instantiated from the Spring Core framework (org.springframework.security.core.userdetails.User). This constructor is asking 7 parameters as you said:

public User(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection authorities) { .. }

There is also one other (overloaded) method which asks just 3 parameters:

public User(String username, String password, Collection authorities) { .. }

Yogesh Chavan
8 years ago

Hello , can someone please explain how password is getting verified here ? As I see the db query is getting the user with only username.

Morteza Malvandi
8 years ago

I’m developing an restful application using Spring And Hibernate. I don’t have Login page, I will be very grateful, if you present all of us that How implement this?

Willians Martins
8 years ago

Very nice your post, every help us, thanks. Can you help more one time? I want to implement the save method in UserDAOImpl class. But the password is not encrypt. My code:

@Override

public T create(T t) {

Session session = sessionFactory.getCurrentSession();

session.save(t);

session.flush();

return t;

}

Thanks again

Gustavo Rozolin
8 years ago

Mkyong I was following the tutorial, then I get an error and I add a question to stackover flow. http://stackoverflow.com/questions/33205236/spring-security-added-prefix-role-to-all-roles-name

Prabhat Singh
6 years ago

please share log or exception

perrohunter
8 years ago

After this I can’t access the tomcat manager at http://localhost:8080/manager/html any ideas on how to add an exception for that path?

metalHead
8 years ago

can’t even build it with maven

Shashank K
8 years ago

Hi Mkyong, Thanks for the nice tutorial. Works great! I want to some more methods in controller to handle post requests. But I get ”
The specified HTTP method is not allowed for the requested resource (Request method ‘POST’ not supported)” error. Please help to solve this

bill gates
8 years ago

thanks, idiom)): return (User( sessionFactory.getCurrentSession()
.createQuery(“from User where username=?”)
.setParameter(0, username)
.list().get(0);

Stefano
8 years ago

To resolve Invalid username and password
This application use the BCryptPasswordEncoder.
Instead of ‘123456’ use ‘$2a$10$NZ0s/78owi0SSVkNdDcEQ.EPW4u5r.HDSqjXZbOOzYUBc1JrzGbHC’
work for me.
For next pass you must encode that with:
String password = “123456”;
PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String hashedPassword = passwordEncoder.encode(password);

GodBlessYou
8 years ago

very nice tutorial..thank you 🙂

Techie Me
8 years ago

I have started a new tutorial where I will be developing a production quality J2EE web application from scratch using annotation based Spring, Hibernate, AOP, Transaction Management and many other technologies. Please have a look http://techieme.in/shop-smart-spring-application-setup/

javaCode coder
9 years ago

share jsp page

human
9 years ago

hi,

what is the salt. How is the password generated? I want to add registration feature

Alex
9 years ago

I’ve made according to this article and i get

jan 13, 2015 12:51:05 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
ERROR: operator does not exist: character varying = bytea

I’m new into hibernate and Spring, but I’ve checked all dependencies, versions and options to find the mistake I’ve made. Still nothing((

shiva
9 years ago

When trying to run the application and loading admin page, login
form opens, but, even after supplying username as ‘mkyong’ and password
as ‘123456’. It always displays ‘Invalid username and password’. Not
able to resolve myself even after trying for two days, can somebody help
me.

Stefano
8 years ago
Reply to  shiva

This application use the BCryptPasswordEncoder.
Instead of ‘123456’ use ‘$2a$10$NZ0s/78owi0SSVkNdDcEQ.EPW4u5r.HDSqjXZbOOzYUBc1JrzGbHC’
work for me.
For next pass you must encode that with:
String password = “123456”;
PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String hashedPassword = passwordEncoder.encode(password);

Batbold Boldbayar
7 years ago
Reply to  Stefano

tnx

Surya
7 years ago

I am getting the same error i.e: always displays ‘Invalid username and password’. Please some body help me out

Batbold Boldbayar
7 years ago
Reply to  Surya

just remove passwordEncoder or put $2a$10$NZ0s/78owi0SSVkNdDcEQ.EPW4u5r.HDSqjXZbOOzYUBc1JrzGbHC to your database passwordfield and use 123456 on web password field.

Willians Martins
8 years ago
Reply to  Stefano

Hello Stefano, talking about this, I try to implement the createUser in DAO class and my password is not encrypt, then I try to write like this:

public T create(T t) {
Session session = sessionFactory.getCurrentSession();
User user = (User) t;
user.setPassword(passwordEncoder.encode(user.getPassword()));
session.save(user);
session.flush();
return t;
}

this will save the password encrypt, but when I login, the user and password the message is “invalid user or password”, can you help me?

Willians Martins
8 years ago

Resolved! I forgot to set the Role, thanks

shiva
9 years ago

i didnt get any solution

shiva
9 years ago

pls give me the solution i also checked db conections and catalog in db

shiva
9 years ago

When trying to run the application and loading admin page, login
form opens, but, even after supplying username as ‘mkyong’ and password
as ‘123456’. It always displays ‘Invalid username and password’. Not
able to resolve myself even after trying for two days, can somebody help
me.

Mehrdad Norouzi
8 years ago
Reply to  shiva

Is the problem solved? (mkyong _ 123456)
Please let me know.

deepak
6 years ago

use password in AppConfig
ds.setUsername(“root”);
ds.setPassword(“root”);

ronny
9 years ago

can you pls give me database script ???

Sandeep
9 years ago

Hi MkYong, Thanks for great article. One question as why did yo first created set of setAuths and then converted to list.can we use list in first place and then return as list?

chris
9 years ago
Reply to  Sandeep

A set ensures unique items, so that way no auth would be added twice, and then it’s converted to a list since lists are easier to manipulate than sets

Sreejith
9 years ago

set you DB password in AppConfig.java

ds.setUsername(“root”);

ds.setPassword(“********”);

return ds;

Tan Nguyen
9 years ago
Reply to  Sreejith

Then I added a password but it still does not work, even though I have entered the correct username and password, it always returns “Invalid username and password!”

Kurniawan
9 years ago

good tutorial!
but how to add user with role ?

Sourav Ken
9 years ago

Try to check your pojo. There catalog my have different schema then what ever schema you are using. Same issue I face when my db name and what is present under catalog in pojo is not same.

Tushar
9 years ago

Where is login page verifies the username entered in username and password with the database? Please guide me, I am new to spring MVC wiring!