Friday, January 13, 2012

Spring Security 3.1 - Implement UserDetailsService with Spring Data JPA (Part 2)

Review

In the previous section, we have laid down the functional specs of the application. In this section, we will discuss the project's structure, write the Java classes, and organize them in layers.


Project Structure

Our application is a Maven project and therefore follows Maven structure. As we create the classes, we've organized them in logical layers: domain, repository, service, and controller.

Here's a preview of our project's structure:

The Layers

Domain Layer

This layer contains two domain classes, User and Role. They represent our database tables, user and role respectively. Because we're developing a JPA-based repository, both classes must be annotated with JPA annotations.




Specifying the entity name inside the @Entity is not required. However, I've encountered instances where the tables are created in lowercase and uppercase, i.e user and USER. For consistency, I've specified them here.

Controller Layer

This layer contains two controllers, AccessController and MediatorController.
  • AccessController is responsible for handling access related requests, mainly login and logout requests
  • MediatorController is responsible for handling requests to common pages such as user and admin pages




Service Layer

This layer contains a single service, CustomUserDetailsService. Its main purpose is to retrieve user information from our custom database and translate that user information into a format that Spring Security understands. Take note of the helper methods provided within this class.



What's the logic here?
  1. We must implement UserDetailsService because we have a custom database
  2. loadUserByUsername method must return an object that implements the UserDetails interface
  3. We must map our domain org.krams.domain.User to org.springframework.security.core.userdetails.User
  4. We must map numerical roles as SimpleGrantedAuthority objects
  5. We are responsible for interpreting what each numerical role value represents
  6. ROLE_USER and ROLE_ADMIN are abitrary values we assigned to numerical values

Repository Layer

This layer contains a single interface, UserRepository. And this is our data access object (DAO). With the help of Spring Data JPA, Spring will automatically provide the actual implementation.

What is Spring Data JPA?
Spring JPA is part of the umbrella Spring Data project that makes it easy to easily implement JPA based repositories.

Implementing a data access layer of an application has been cumbersome for quite a while. Too much boilerplate code has to be written to execute simple queries as well as perform pagination, and auditing. Spring JPA aims to significantly improve the implementation of data access layers by reducing the effort to the amount that's actually needed. As a developer you write your repository interfaces, including custom finder methods, and Spring will provide the implementation automatically.

Source: http://www.springsource.org/spring-data/jpa



Utility classes

TraceInterceptor class is an AOP-based utility class to help us debug our application. This is a subclass of CustomizableTraceInterceptor (see Spring Data JPA FAQ)



Next

In the next section, we will focus on the configuration files and create them accordingly. Click here to proceed.
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring Security 3.1 - Implement UserDetailsService with Spring Data JPA (Part 2) ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

16 comments:

  1. grate.....tutorial

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete
  3. Great tutorial, but I need an explanation.

    How can you return a new User in loadUserByUsername if your User class doesn't implement UserDetails class?

    ReplyDelete
  4. @Nenaza, you cannot return a new User if it doesn't implement the UserDetails interface. However, if you examine carefully the CustomUserDetailsService class, we're able to return a new User. That's because it's implementing the UserDetails interface. And the user we're referring to is from the package org.springframework.security.core.userdetails.User and we're mapping from org.krams.domain.User. In other words, there are two User classes in this tutorial. See http://static.springsource.org/spring-security/site/docs/3.1.x/apidocs/index.html for details

    ReplyDelete
  5. Hi Krams when i run this example project i am getting this exceptions please help me

    1)javax.persistence.PersistenceException: [PersistenceUnit: hibernatePersistenceUnit] Unable to build EntityManagerFactory

    2)org.hibernate.MappingException: Could not determine type for: com.manam.domain.Role, at table: user, for columns: [org.hibernate.mapping.Column(role)]

    ReplyDelete
  6. /* Excuse me for my english */
    First, I thank Mr. Krams for this very interesting tutorial. and i wonder if
    someone can help me by posting an updated pom.xml for this project, in fact there is some problems in the "goldin" dependency.
    thank you

    Note: the probem remains even if we update the pom.xml as it indicated by Mr.Krams somewhere here in a comment

    ReplyDelete
  7. HI Krams

    Please Explain the spring AOP . i did not understand this concept. why we using Traceinterceptor.java file

    ReplyDelete
    Replies
    1. @Dummy, this is use for debugging purposes. So that we can lessen the need of manually adding trace statements in each method just to see what's coming in and what's coming out. The value is easy troubleshooting.

      Delete
  8. Hi Krams,
    First of all i would like to thank you for this wonderfull tutorial...

    I changed the spring JPA to hibernate sessionFactory and when i run the application the CustonmUserDetailsService loadUserByUsername method is not getting called

    ReplyDelete
    Replies
    1. The best way to troubleshoot this problem is to enable DEBUG-level logging.

      Delete
  9. Hello Krams,
    thank you for this great tutorial.
    I was looking about how to integrate Spring Security and JPA and probably your posts will help me a lot.

    The point is that I have already developed in my Spring MVC my DAO Layer.
    I have not used @Repository annotations yet and either Spring Data JPA.

    Is that possible to use simple JPA layer as I have developed with the architecture you have suggested? I mean, what is the benefit of using Spring Data JPA over traditional JPA?
    Is the configuration going to change a lot using JPA only?

    This is how my JPA works:

    public class UsuarioJPADAO implements UsuarioDAO{

    private EntityManager entityManager;

    @Override
    public void setEntityManager(EntityManager em) {
    this.entityManager = em;
    }

    @Override
    public Collection findByName(String name) throws DAOException {
    Query query = entityManager.createNamedQuery("Usuario.findByName");
    query.setParameter("name", name);
    return query.getResultList();
    }


    Thank you and regards.

    ReplyDelete
  10. Thanks for amazing Spring security series, all of them

    Incredibly well written articles. Much better than tutorial provided by Spring

    ReplyDelete
  11. Thanks for the tutorial. I am having an compilation error with loadUserByUsername returning UserDetails. Any suggestions.

    ReplyDelete
  12. My issue turned out to be POM related. I needed all to surrounded by and that fixed my Lifecycle issues. SpringData then was able to populate the loadUserByUsername return UserDetails.

    ReplyDelete
  13. all plugin elements must be in a pluginManagement, plugins elements in the POM. The comments don't accept < and >

    ReplyDelete
  14. hello; i dont understand in the getRoles method in CusomUserDetailsService, the integer represents what? can you explain

    ReplyDelete