How to configure Spring Security using Hibernate with Spring MVC
April 1, 2014
Java is almost always giving me a bit of a hard time. I run into problems every now and then, so I start looking for answers on Google. Coming from PHP I am used to finding the answers within one query on your favorite search engine. However, with Java this is almost never the case.
I always have to view at least the first ten results to forge the answer to the problem I am having. This was also the case with configuring Spring MVC, Spring Security and Hibernate. And when you’ve figured it out, it’s quite simple actually.
First of, if you haven’t yet, add Spring Web Security to your Maven file:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>3.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>3.2.2.RELEASE</version>
</dependency>
3.2.2
is the latest version at the moment of writing.
Alright, when this is installed it is time to configure your web application. I assume you know how to create an Entity within Hibernate, so I am not going to cover that.
First off, the configuration:
Add this to web.xml
:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/mvc-dispatcher-servlet.xml
</param-value>
</context-param>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Keep in mind, my web.xml was rather plain because I started out with a pretty clean project, this could be different for you. Also mind the name mvc-dispatcher-servlet.xml
could be named differently in your project.
If you haven’t added the XML security namespaces to your project yet, it’s time to do so now:
xmlns:security="http://www.springframework.org/schema/security"
And add this to your schemaLocation
:
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd
So this will make your XML header look something like this:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd
">
Then, add this to mvc-dispatcher-servlet.xml
:
<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
<security:http auto-config="true">
<security:intercept-url pattern="/members/*" access="ROLE_USER" />
<security:form-login login-page="/login" default-target-url="/"
authentication-failure-url="/login/failed" />
<security:logout logout-success-url="/" />
</security:http>
<security:authentication-manager>
<security:authentication-provider user-service-ref="userDetailsService">
<security:password-encoder ref="passwordEncoder" />
</security:authentication-provider>
</security:authentication-manager>
As you can see here I declare a passwordEncoder
, using the BCryptPasswordEncoder
provided by the Spring Framework. This is by more secure than SHA-1 or MD5 (just do a google search on this subject).
Another perhaps interesting fact is that I refer to the service userDetailsService
here. We will declare this now, it is used to build our user objects.
UserDetailsService.java
:
@Service("userDetailsService")
public class UserDetailService implements UserDetailsService {
@Autowired
@Qualifier("userDao")
private IUserDao userDao;
@Autowired
private Assembler assembler;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userDao.findByEmail(username);
if (user == null)
throw new UsernameNotFoundException("User not found");
return assembler.buildUserFromEntity(user);
}
}
And as you can imagine, we will need to declare the Assembler
as well. I assume you know how the UserDAO
works, or how it’s supposed to work. At the very least it should have a method that queries a user by email address or username.
Assembler.java
:
@Service("assembler")
public class Assembler {
@Transactional
public User buildUserFromEntity(com.mtech.easyexchange.model.User user) {
String username = user.getEmail();
String password = user.getPassword();
boolean enabled = true;
Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
return new User(username, password, enabled, enabled, enabled, enabled, authorities);
}
}
As you can see I simply add a SimpleGrantedAuthority
hardcoded to the user: ROLE_USER
. What you could do is create an entity holding UserRoles and load them from the database.
This pretty much concludes the very basic configuration of Spring Security using Hibernate 4.3 with Spring MVC 4.