Spring Security UserDetailsService Example

Learn to custom UserDetailsService implementation in your Spring application’s authentication-provider to fetch custom User object, and way to use it in your application.

Spring UserDetailsService Interface

UserDetailsService interface is used in order to lookup the username, password and GrantedAuthorities for any given user.

This interface provide only one method which implementing class need to implement-

UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;

Here UserDetails is container for core user information. According to docs, its implementations are not used directly by Spring Security for security purposes. They simply store user information which is later encapsulated into Authentication objects. This allows non-security related user information (such as email addresses, telephone numbers etc) to be stored in a convenient location. A very good sample implementation can be like User class.

In this example, AuthenticationProvider authenticates the user simply by comparing the password submitted in a UsernamePasswordAuthenticationToken against the one loaded by the UserDetailsService.

UserDetailsService Implementation

1) Configure authentication-provider

I am taking forward the code base as written in Spring login form based security. In the application-security.xml file, I will update the configuration to use EmployeeDao as custom user detail service.

< ?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
	http://www.springframework.org/schema/security/
	http://www.springframework.org/schema/security/spring-security-3.0.3.xsd">

	<http auto-config="true"  use-expressions="true">
		<intercept-url pattern="/login" access="permitAll"></intercept-url>
		<intercept-url pattern="/logout" access="permitAll"></intercept-url>
		<intercept-url pattern="/accessdenied" access="permitAll"></intercept-url>
		<intercept-url pattern="/**" access="hasRole('ROLE_USER')"></intercept-url>
		<form-login login-page="/login" default-target-url="/list" authentication-failure-url="/accessdenied"></form-login>
		<logout logout-success-url="/logout"></logout>
	</http>

	<authentication-manager alias="authenticationManager">
		<authentication-provider user-service-ref="employeeDAO" />
	</authentication-manager>

</beans:beans>

2) Configure dataSource

Also, the complete employee-servlet.xml file look like this:

< ?xml  version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xmlns:lang="http://www.springframework.org/schema/lang"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop/ http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context/ http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/jee/ http://www.springframework.org/schema/jee/spring-jee.xsd
        http://www.springframework.org/schema/lang/ http://www.springframework.org/schema/lang/spring-lang.xsd
        http://www.springframework.org/schema/tx/ http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/util/ http://www.springframework.org/schema/util/spring-util.xsd">

    <context:annotation-config />
    <context:component-scan base-package="com.howtodoinjava.controller" />

    <bean id="jspViewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass"
            value="org.springframework.web.servlet.view.JstlView"></property>
        <property name="prefix" value="/WEB-INF/view/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

    <bean id="messageSource"
        class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basename" value="classpath:messages"></property>
        <property name="defaultEncoding" value="UTF-8"></property>
    </bean>

    <bean id="propertyConfigurer"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
        p:location="/WEB-INF/jdbc.properties"></bean>

    <bean id="dataSource"
        class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
        p:driverClassName="${jdbc.driverClassName}"
        p:url="${jdbc.databaseurl}" p:username="${jdbc.username}"
        p:password="${jdbc.password}"></bean>

    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <property name="configLocation">
            <value>classpath:hibernate.cfg.xml</value>
        </property>
        <property name="configurationClass">
            <value>org.hibernate.cfg.AnnotationConfiguration</value>
        </property>
        <property name="hibernateProperties">
           <value>
            hibernate.connection.provider_class=org.hibernate.connection.C3P0ConnectionProvider
            hibernate.dialect=org.hibernate.dialect.SQLServer2008Dialect
            hibernate.default_schema=dbo
            hibernate.show_sql=true
       		</value>
        </property>
    </bean>

    <bean id="employeeDAO" class="com.howtodoinjava.dao.EmployeeDaoImpl"></bean>
    <bean id="employeeManager" class="com.howtodoinjava.service.EmployeeManagerImpl"></bean>

    <tx:annotation-driven />
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"></property>
    </bean>

</beans>

3) Implement UserDetailsService in Dao

Now we have to update the EmployeeDaoImpl.java to implement UserDetailsService interface and override method loadUserByUsername().

EmployeeDaoImpl.java

package com.howtodoinjava.dao;

import java.util.List;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
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.Repository;

import com.howtodoinjava.entity.EmployeeEntity;

@Repository
public class EmployeeDaoImpl implements EmployeeDAO, UserDetailsService  {

	@Autowired
    private SessionFactory sessionFactory;

	@Override
	public void addEmployee(EmployeeEntity employee) {
		this.sessionFactory.getCurrentSession().save(employee);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<EmployeeEntity> getAllEmployees() {
		return this.sessionFactory.getCurrentSession().createQuery("from Employee").list();
	}

	@Override
	public void deleteEmployee(Integer employeeId) {
		EmployeeEntity employee = (EmployeeEntity) sessionFactory.getCurrentSession().load(
				EmployeeEntity.class, employeeId);
        if (null != employee) {
        	this.sessionFactory.getCurrentSession().delete(employee);
        }
	}

	@SuppressWarnings("deprecation")
	@Override
	public UserDetails loadUserByUsername(String username)
			throws UsernameNotFoundException, DataAccessException
	{
		System.out.println("Getting access details from employee dao !!");

		// Ideally it should be fetched from database and populated instance of
		// #org.springframework.security.core.userdetails.User should be returned from this method
		UserDetails user = new User(username, "password", true, true, true, true, new GrantedAuthority[]{ new GrantedAuthorityImpl("ROLE_USER") });
		return user;
	}
}

In the above Dao, I have used minimal code to show the usage of involved classes and in enterprise application, a proper access to database should be made and the user’s password and its role should be set.

The whole idea is to return the User instance with populated values inside the method. If your have other requirements, then you are free to implements UserDetails interface also and spring will not prevent you from using it.

Demo

To test the application, simply hit the URL “http://localhost:8080/Spring3HibernateIntegration” in browser window. A login box will appear like below:

default-login-screen-spring-security-8277980

Now login with correct username and password (i.e. lokesh and password) will let you enter into the application and employee management screen will appear. Otherwise access denied page will shown as below:

unauthorized-access-spring-security-1876940

Happy Learning !!

Was this post helpful?

Join 7000+ Fellow Programmers

Subscribe to get new post notifications, industry updates, best practices, and much more. Directly into your inbox, for free.

46 thoughts on “Spring Security UserDetailsService Example”

  1. Hi Lokesh, Here is one doubt, if one user is having multiple roles then how to handle this in this example.

    Thanks.
    Debendra.

  2. Hi Lokesh,

    The tutorial is really great! Appreciated!
    I had one question though –

    Can we somehow externalize the mappings of URL vs corresponding permissions in database instead of security.xml?
    What I’m trying to say is that, instead of hardcoding the permissions for resources in the xml like following –

    can we have this thing configurable in the database?

    So I’ve a RESOURCE table, where I’m storing all of my application URLs and I’ve a PERMISSION table where I’m storing all the permissions (like VIEW_USER, EDIT_USER etc) and I’ve a mapping table which map RESOURCE_ID to PERMISSION_ID.
    So, I can’t configure the mapping in the xml.

    So is there any way by which I can externalize these mapping in the DB and use spring security to implement access control?
    And this is the real life scenario. Any real application will have hundreds of URLs and it is not feasible to configure it XML. It should use external tables and spring should use the tables to control access.

    Any idea regarding how we can achieve this?

    Thanks,
    Umesh.

    • Sorry I missed the xml code. It goes like this –

              <intercept-url pattern="/login" access="permitAll"></intercept-url>
              <intercept-url pattern="/logout" access="permitAll"></intercept-url>
              <intercept-url pattern="/accessdenied" access="permitAll"></intercept-url>
              <intercept-url pattern="/**" access="hasRole('ROLE_USER')"></intercept-url>
      
  3. In the same application,
    [1] What I have to do, if I want to integrate user table from where user and password will be fetched? where password is saved in encrypted format in the table.
    [2] On the basis of use login, they should be able to delete employees which are added by them. If they try to delete other employee (by coping link from delete, paste in address bar and change id) it should prompt access denied message.

    • 1) Code will use the method “EmployeeDaoImpl.loadUserByUsername()”. Use your custom logic here.. e.g. hibernate fetch entity code.
      2) This should be done ideally by securing domain objects (using ACLs), but i do not have any concrete helpful information as of now. I will check and update you.

          • I mean, I couldn’t find something on REST API security. What approach to be followed and how? It will be great if you could assist.
            Yes, I have read your article on Big data and I must say It was very impressive and informative.

  4. Hi Lokesh,

    As per loadUserByUsername(String userName){

    } method shown above, you mentioned based on userName we can fetch User data from DB and populate UserDetails object. I don’t have any confusion here. But my query is where we are matching user entered password with User DB password to authenticate user. This is really where I’m lagging to relate the connection. Can you please help me to clarify this?

    • We do not compare in our code, it’s spring which does it for us. You mention “AuthenticationProvider” i.e. bean authentication-manager. It internally asks for a ‘UserDetails’ object which is responsibility of “EmployeeDaoImpl” because we mentioned “authentication-provider user-service-ref=”employeeDAO””. Inside framework code, spring matches password stored in “UserDetails” object and one supplied by user in form.

        • Then you need to pass one extra bean param as below:

          &amp;lt;!-- Configure appropiate encoder --&amp;gt;
          &amp;lt;beans:bean id=&amp;quot;encoder&amp;quot; 
          	class=&amp;quot;org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder&amp;quot;&amp;gt;
          	&amp;lt;beans:constructor-arg name=&amp;quot;strength&amp;quot; value=&amp;quot;11&amp;quot; /&amp;gt;
          &amp;lt;/beans:bean&amp;gt;
          
          &amp;lt;!-- Pass the encoder here --&amp;gt;
          &amp;lt;authentication-manager alias=&amp;quot;authenticationManager&amp;quot;&amp;gt;
          	&amp;lt;authentication-provider user-service-ref=&amp;quot;employeeDAO&amp;quot; /&amp;gt;
          	&amp;lt;password-encoder ref=&amp;quot;encoder&amp;quot; /&amp;gt;
          &amp;lt;/authentication-manager&amp;gt;
          

          A good reference is here.

  5. Nice article.
    Do you have some POCs where the user is already authenticated by third party system like LDAP and uses spring security for authorization. I know there are hundred of examples on internet for this, but none of them explains how to create a UserDetails object using HTTP request headers and create appropriate roles based on the group name received in the request header. I tried all pre authentication ways but none of them help as they relay on user details service implementation which has only one method with just one parameter i.e username.

    Any pointer would help.

  6. Hi I have followed this and got it correct πŸ™‚ Thanku for the post πŸ™‚ Can you help me out the same for security ldap server??

  7. hi i dont want to display that access denied page instead i need to display error message in index.jsp page and i let the user to to login thereonly

    • Spring docs suggest to use a request parameter in login url itself. They says:

      Maps to the authenticationFailureUrl property of UsernamePasswordAuthenticationFilter. Defines the URL the browser will be redirected to on login failure. Defaults to “/spring_security_login?login_error”, which will be automatically handled by the automatic login page generator, re-rendering the login page with an error message.

      So basically you have to define authentication-failure-url=”/login?error_code=1″ and use it code somewhere in your JSP like this:

      <c:if test=”${param.error_code == ‘1’}”>
      <span><spring:message code=”loginPage.authenticationFailure” /></span>
      </c:if>

  8. Hi sir,I used Spring Security UserDetailService in my project and if valid user,its working fine.Iam having some doubts related to Httpsession sir.after the login through spring security,i want to set some flags after successful login ,in loadUserByUsername() again i have to make a call to DB sir.and another one is i want to make some objects into sessionScope,requestScope,is it like General way of Creating HttpSession in spring also sir or any other way is there.because iam working in cluster servers sir,session is always broken sir.Please Help me sir.Thanks

  9. thanks Lokesh for the response but as I see in the link there is the code sourse for jdbc user service. So,I have to do the above changes over this code?thx

  10. Hi,
    Could you tell me please where i can find the entire source code for this (custom UserDetailService). I didn’t understood very well…this tutorial is based on Spring 3 hibernate integration example? Thanks in advance.

  11. hey i am looking for a example on login authentication with table have user and pass with a no of user in the table
    need to get login by the specific username and password using spring mvc+springsecurity +hibernate please do suggest me

  12. Can you post some example on the below requirement
    my application User is pre-authenticated via third party system and third party system will pass the userid as the request parameter to my application
    I want to use Spring security only for authorization (roles are stored in database)”

    • Well, first of all that is not the subject of post. I am saying this so other visitors of this page does not get confuse by my argument.
      My take on your question is that it neither will prove effective, if used carelessly. Its not hibernate or JDBC which makes program secure, its how you use them to secure your application.
      JDBC has very low level APIs which makes it more vulnerable if used incorrectly. Hibernate on other hand take care of some basic things, but still you need to do a lot of things extra. to make your application robust and secure.

Comments are closed.

HowToDoInJava

A blog about Java and its related technologies, the best practices, algorithms, interview questions, scripting languages, and Python.