Writing custom UserDetailsService for spring security
I wish spring security would work on their documentation and tell people how easy it is to implement a custom service for loading user details. You don’t HAVE to use JDBC to do that, you can write your very own hibernate, toplink or whatever DAO to do just that. It’s important to realise that spring-security does not send your password to the database ever. Instead it loads a user’s details and then compares it’s password internally before validating the user and granting it access to internal pages.
In my case I did not want to maintain a list of authorities because there were ever only going to be two kinds of user’s, admins and non-admins. Administrator access was to be determined by a boolean field in the table. So I needed to override the queries that the default UserDetailsService implementation, JdbcDaoImpl uses and also set an extra role for user’s who were admins. It sounds simple and it actually is simple only if you don’t dive into the documentation.
The table structure and some data (in postgresql) :
CREATE TABLE test.users ( id integer NOT NULL, name character varying(100) NOT NULL, email character varying(100) NOT NULL, "admin" boolean DEFAULT false, "password" character varying(20) ) WITH (OIDS=FALSE); INSERT INTO test.users VALUES (1, 'normal user 1', 'normal@email.com', 'f', 'pass1'); INSERT INTO test.users VALUES (2, 'normal user 2', 'normal2@email.com', 'f', 'pass2'); INSERT INTO test.users VALUES (3, 'admin user 1', 'admin@email.com', 't', 'pass3');
Remember that UserDetailsService is only used to lookup the user and not perform any sort of validation etc. Implementation of such a service would be :
package com.codercorp.dwr;
//imports
public class MyUserDetailsService implements UserDetailsService {
private DataSource dataSource;
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException, DataAccessException {
String sql = "select * from user where email like :username";
MapSqlParameterSource source = new MapSqlParameterSource();
source.addValue("username", username);
SimpleJdbcTemplate sjt = new SimpleJdbcTemplate(getDataSource());
User user = sjt.queryForObject(sql, new UserMapper(), source);
return user;
}
private GrantedAuthority[] getAuthorities(boolean isAdmin) {
List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>(2);
authList.add(new GrantedAuthorityImpl("ROLE_USER"));
if (isAdmin) {
authList.add(new GrantedAuthorityImpl("ROLE_ADMIN"));
}
return authList.toArray(new GrantedAuthority[] {});
}
private class UserMapper implements ParameterizedRowMapper<User> {
@Override
public User mapRow(ResultSet rs, int arg1) throws SQLException {
return new User(rs.getString("email"), rs.getString("password"), true, true, true, true, getAuthorities(rs.getBoolean("admin")));
}
}
}
The User object that loadByUsername returns is of the class org.springframework.security.userdetails.User. We don’t really need extra functionality for this tutorial but if you do, you can simply extend this class or alternatively implement org.springframework.security.userdetails.UserDetails. As is evident from the code all we do is add a ROLE_USER to every user who’s details we obtain and another ROLE_ADMIN for every user that is marked as an admin. We also use the email address as the login credential and as the name of the user, nothing wrong with that and you can change that anytime you like by extending the org.springframework.security.userdetails.User class.
Now for the spring security configuration. This is the tricky part and if you haven’t done this before I strongly suggest you read my earlier article on configuring the basics. If you go looking on the web, you’ll see a lot of people talking about authentication providers and what not. Thats only neccessary when you plan to authenticate user’s using some other way instead of their input details. If you just want to use a database then the following two lines in your security-applicationContext.xml are more than enough :
<b:bean id="customUserDetailsService" class="com.codercorp.npdac.security.MyUserDetailsService"> <b:property name="dataSource" ref="dataSource" /> </b:bean> <s:authentication-provider user-service-ref="customUserDetailsService" />
Those are the ONLY lines that you need to add to your configuration file. It’s pretty easy to see that all we’re doing is instantiating our user details service and then telling our AuthenticationProvider, DaoAuthenticationProvider by default, to use our service to retrieve user details. I did run into a problem while configuring spring security and recieved a org.springframework.security.providers.ProviderNotFoundException but that was only because I had set auto-config attribute of the http element to false because of which the default authentication provider was not initialized.
Your webapp can now use custom tables to implement it’s security.

By just adding something like the following to the configuration file it works too (but I’m using an Oracle database)
wow thanks so much for this man. ill try it out. hope it works for me.
Hey its me again. i have a question. i have a user table similar to yours. the thing is, i need to pass the id of the user to the next page when the log-in is successfull. i was wondering how to do this.
(i have a hunch that maybe it has something to do with the form-login
default-target-url but i could be dead wrong)
thanks so much.
You can get the user object itself on the next page using SecurityContextHolder.getContext().getAuthentication().getPrincipal(). But you really shouldn’t have to access the user’s ID on the jsp page. All that should be done in the controller.
Hi,
While I have been able to customize the JasperServer to use existing iBatis/Struts infrastructure and integrate authentication using existing app, there is one thorn. How can I change the login page to accept another field? Say I want user to enter Domain in addition to username and password. And use the three to authenticate and eventually show reports. I have been able to write my custom Dao that validates jasper user from my DB, but how do I get new attribute – domain to reach my Dao, so that it can be used to authenticate the user? While customizing the login page to accept additional fields is straightforward – you just need to modify login.jsp and make it your login page – making the new values reach \’some Java handler\’ is an issue.
Appreciate inputs on this.
testing the test
Hi,
This was a very useful article
I have a requirement, which is the user account has to be locked after 5 consecutive failed attempts. How can this be acheived. I have to store the details like “First Failed Try Time” and “Locked Flag” in the database.
So basically, I have to customize something after the passwords mismatch. Iam not sure how this is done. Given that iam using Spring’s Form based authentication. Where should i write this Logic??
If any one has got any idea PLEASE..E share.
Regards,
Sajitha
Thanks for the tutorial, I’m new to Spring Security and it really helped me out!
I want to return my own user Object (with extra parameters ), so I created a custom UserDetailsService and extended org.springframework.security.userdetails.User.
However in my client side application (on successful login) an Object with two parameters is returned:
– authorites
– name (which is the username)
Below is a snippet of my custom UserDetailsService:
public MyUser loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
String sql = “select * from user where emailAddress like :username”;
MapSqlParameterSource source = new MapSqlParameterSource();
source.addValue(“username”, username);
SimpleJdbcTemplate sjt = new SimpleJdbcTemplate(getDataSource());
MyUser user = sjt.queryForObject(sql, RowMapperUtil.getUserRowMapper(), source);
return user;
}
I’m a bit lost here! I am returning an Object of type MyUser and mapping all the fields correctly, so I am not sure where I am going wrong.
Your help is greatly appreciated,
Daniel
Concise, to-the-point and _exactly_ what I was looking for. Thanks!
Kudos for the simplicity and objetctiviy. Saved me a lot of time.
Thank very much…
Code is works.
Gaurav,
Thank you so much for this blog post. I wasn’t able to really get how authorization worked in Spring Security until reading this. I left a message on the spring forums saying that they should improve their docs and put more details on how to customize the UserDetailsService.
nice coding friends! please visit me back too!
Dude….u’r examples are a saviour compared to the documentation provided.
Above u have used a DB to get the user details.
But could u guide me in finding the solution. I need client Website to be authenticated using spring-security with CAS and the user credentials are in Oracle bpm directory. trouble is neither spring security nor oracle bpm directory give access to password information.
In above scenario hw to get a work around for the user authentication.
Any kinda guidance appreciated.
Hi… I am very new to this spring security. i followed the above steps. I have some doubts.
1. From Where i need to call this service.
2. Where to set the the return value user object.
Please reply me…
Thanks
Helpful, thanks
Hi there,
I tried using your code. I have a reference to UserDetailsService(customized) that i have written just like you. But, the authentication does not happen and everytime, it takes the role of anonymous user. What am I missing?
I would appreciate if you could get back to me quickly
Priya
Java Blog
Hey, this post is great!! I had a different DB structure than suggested by Spring Security and with this I can match my DB schema without creating new tables… Thanks a lot!!
hi,
i have 2 questions:
1.
private class UserMapper implements ParameterizedRowMapper {
@Override
public User mapRow(ResultSet rs, int arg1) throws SQLException {
return new User(rs.getString(“id_user”), rs.getString(“password_2″), true, true, true, true, getAuthorities(rs.getBoolean(“admin”)));
}
}
new User(rs.getString(“id_user”), rs.getString(“password_2″), true, true, true, true, getAuthorities(rs.getBoolean(“admin”)));
this method is deprecated, what other way can i implement this.
2. i have a separate table for users and roles both tables use a join table. how can i get the roles and implement it in this way?
Thanks for this example. It saved my day.
Im using JPA config in persistence.xml with eclipselink and jndi datasource.
I lost all day trying to inject JPA EntityManager (with @PersistenceContext annotation) or DAO object (with @EJB annotation) but it failed – both were NULL.
So I will go with your example with injecting “dataSource”.
Thanks a ton mate, great post!
information. I am social bookmarking and will be tweeting this precise to my own fans! Wonderful blog site and also excellent design and style.
pretty helpful tutorial. it saves my time.
Hi I implemented in the same way as it was described. But got an error. My custom UserDeatilsService is nopt getting called. And the user is always getting redirected to authentication-failure-url. I dont know why it is happening please help.
I have a requirement, which is the user account has to be locked after 5 consecutive failed attempts. How can this be acheived. I have to store the details like “First Failed Try Time” and “Locked Flag” in the database.
Hi there, I enjoy reading all of your article. I wanted
to write a little comment to support you.
I must thank you for the efforts you’ve put in writing this blog. I’m hoping to view
the same high-grade content by you in the future as well.
In truth, your creative writing abilities has inspired me to get my very own blog now
Excellent article. Keep posting such kind of information on your site.
Im really impressed by it.
Hey there, You have done an excellent job. I will definitely digg it and individually recommend to my
friends. I am sure they will be benefited from this site.
Ginger can even cure a lot of ailments apart from its wonderful flavors.
Then he stood up and, as best as I can describe it, hugged me.
The string needs to be long enough to secure the bag and to be tied to the
saucepan handle to reach the bottom of the pan.
Attractive component to content. I simply stumbled upon your site and in accession capital
to assert that I get in fact enjoyed account your blog posts.
Anyway I’ll be subscribing on your feeds or even I fulfillment you get right of entry to constantly quickly.
I really love your website.. Excellent colors & theme. Did you build this
amazing site yourself? Please reply back as I’m trying to create my own personal website and would love to learn where you got this from or what the theme is called. Cheers!
Use finger and thumb pressure on the big areas,
like the ball of the foot and heel. While many people would believe that coconut milk and coconut oil are unhealthy because of their high saturated fat content, this oil is actually an incredibly healthy food source.
Olive oil is also good, but not after it has been heated.
Pretty! This has been a really wonderful article. Thanks for providing this
info.
Asking questions are genuinely pleasant thing if
you are not understanding something totally, however this piece of
writing provides good understanding yet.
Hi! Someone in my Facebook group shared this site with us so I came to look it over.
I’m definitely enjoying the information. I’m bookmarking and will be tweeting this to my followers!
Outstanding blog and wonderful style and design.