In the last tutorial we used default database configuration required by Spring Security and we moved out of hard coded user credentials.
But there is every possibility that their is already a existing database for user management and we cannot create new tables as required by Spring Security default behavior.
This can be achieved very easily in few steps, let’s see it in action.
First we have to create a new class which will extend JdbcDaoImpl
, currently we don’t have any other functionality to place inside our custom implementation, so we will just extend the default behavior provided by JdbcDaoImpl
, but in real world you can have many other functionality as part of your implementation.
CustomJDBCDaoImpl.java
package com.mumz.jsfspringsec.dao; import org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl; public class CustomJDBCDaoImpl extends JdbcDaoImpl { public CustomJDBCDaoImpl(){ super(); } }
Second we need to update our jsfspring-sec-bean-config.xml
and add the custom implementation.
jsfspring-sec-bean-config.xml
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:sec="http://www.springframework.org/schema/security" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd" > <beans:bean id="navigator" name="navigator" class="com.mumz.jsfspringsec.beans.Navigator" scope="session"> </beans:bean> <beans:bean id="loginBean" name="loginBean" class="com.mumz.jsfspringsec.beans.LoginBean" scope="prototype"> <beans:property name="authenticationManager" ref="authenticationManager"></beans:property> <beans:property name="rememberMeServices" ref="rememberMeServices"></beans:property> <beans:property name="userDetailsService" ref="customjdbcUserService"></beans:property> </beans:bean> <beans:bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <beans:property name="driverClassName" value="com.mysql.jdbc.Driver" /> <beans:property name="url" value="jdbc:mysql://localhost:3306/jsf-spring-security" /> <beans:property name="username" value="root" /> <beans:property name="password" value="root" /> </beans:bean> <beans:bean id="customjdbcUserService" class="com.mumz.jsfspringsec.dao.CustomJDBCDaoImpl"> <beans:property name="dataSource" ref="dataSource"/> <beans:property name="enableAuthorities" value="true"/> <beans:property name="usersByUsernameQuery"> <beans:value>SELECT JSF_SPRING_SEC_USERS_USERNAME, JSF_SPRING_SEC_USERS_PASSWORD, JSF_SPRING_SEC_USERS_ENABLED FROM JSF_SPRING_SEC_USERS WHERE JSF_SPRING_SEC_USERS_USERNAME = ?</beans:value> </beans:property> <beans:property name="authoritiesByUsernameQuery"> <beans:value> select JSF_SPRING_SEC_ROLES_USERNAME,JSF_SPRING_SEC_ROLES_ROLE_NAME from JSF_SPRING_SEC_ROLES where JSF_SPRING_SEC_ROLES_USERNAME = ? </beans:value> </beans:property> </beans:bean> <beans:bean id="rememberMeServices" class="org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices"> <beans:property name="key" value="jsfspring-sec" /> <beans:property name="userDetailsService" ref="customjdbcUserService" /> <beans:property name="alwaysRemember" value="true" /> <beans:property name="tokenValiditySeconds" value="60" /> </beans:bean> <beans:bean id="rememberMeAuthenticationProvider" class="org.springframework.security.authentication.RememberMeAuthenticationProvider"> <beans:property name="key" value="jsfspring-sec"/> </beans:bean> <beans:bean id="rememberMeFilter" class="org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter"> <beans:property name="rememberMeServices" ref="rememberMeServices"/> <beans:property name="authenticationManager" ref="authenticationManager" /> </beans:bean> </beans:beans>
Important thing to note above:
- Since we are overriding the default behaviour we have to specify queries for loading username and authorities, which is what we have done for
usersByUsernameQuery
andauthoritiesByUsernameQuery
Third step is to use this custom implementation with our authentication manager in jsfspring-sec-security-config.xml
.
jsfspring-sec-security-config.xml
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:sec="http://www.springframework.org/schema/security" xmlns:beans="http://www.springframework.org/schema/beans" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd"> <sec:http auto-config="true" use-expressions="true"> <sec:intercept-url pattern="/pages/secure/**" access="hasRole('ROLE_USER')" /> <sec:intercept-url pattern="/pages/unsecure/**" access="permitAll"/> <sec:intercept-url pattern="/pages/common/**" access="permitAll"/> <sec:intercept-url pattern="/**" access="permitAll"/> <sec:form-login login-page="/pages/common/login.jsf"/> <sec:remember-me key="jsfspring-sec" services-ref="rememberMeServices"/> <sec:logout invalidate-session="true" delete-cookies="JSESSIONID,SPRING_SECURITY_REMEMBER_ME_COOKIE" logout-success-url="/pages/common/login.jsf"></sec:logout> </sec:http> <sec:authentication-manager alias="authenticationManager"> <sec:authentication-provider ref="rememberMeAuthenticationProvider"></sec:authentication-provider> <sec:authentication-provider user-service-ref="customjdbcUserService"> </sec:authentication-provider> </sec:authentication-manager> </beans:beans>
Database schema
delimiter $$ CREATE DATABASE `jsf-spring-security` /*!40100 DEFAULT CHARACTER SET utf8 */$$ CREATE TABLE `jsf_spring_sec_users` ( `PK_JSF_SPRING_SEC_USERS` int(11) NOT NULL AUTO_INCREMENT, `JSF_SPRING_SEC_USERS_USERNAME` varchar(45) NOT NULL, `JSF_SPRING_SEC_USERS_PASSWORD` varchar(255) NOT NULL, `JSF_SPRING_SEC_USERS_ENABLED` varchar(5) NOT NULL, `JSF_SPRING_SEC_USERS_CREATED_DT` varchar(45) NOT NULL, `JSF_SPRING_SEC_USERS_MODIFIED_DT` varchar(45) DEFAULT NULL, PRIMARY KEY (`PK_JSF_SPRING_SEC_USERS`), UNIQUE KEY `JSF_SPRING_SEC_USERS_USERNAME_UNIQUE` (`JSF_SPRING_SEC_USERS_USERNAME`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 CREATE TABLE `jsf_spring_sec_roles` ( `PK_JSF_SPRING_SEC_ROLES` int(11) NOT NULL AUTO_INCREMENT, `JSF_SPRING_SEC_ROLES_USERNAME` varchar(45) NOT NULL, `JSF_SPRING_SEC_ROLES_ROLE_NAME` varchar(45) NOT NULL, `JSF_SPRING_SEC_ROLES_CREATED_DT` varchar(45) NOT NULL, `JSF_SPRING_SEC_ROLES_MODIFIED_DT` varchar(45) DEFAULT NULL, PRIMARY KEY (`PK_JSF_SPRING_SEC_ROLES`), KEY `FK_USERNAME_JSF_SPRING_SEC_ROLES` (`JSF_SPRING_SEC_ROLES_USERNAME`), CONSTRAINT `FK_USERNAME_JSF_SPRING_SEC_ROLES` FOREIGN KEY (`JSF_SPRING_SEC_ROLES_USERNAME`) REFERENCES `jsf_spring_sec_users` (`JSF_SPRING_SEC_USERS_USERNAME`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 INSERT INTO `jsf_spring_sec_users` VALUES (1,'admin','admin','true','2012-07-17 10:07:41','2012-07-17 10:07:41'),(2,'guest','guest','true','2012-07-17 16:59:13','2012-07-17 16:59:13'); INSERT INTO `jsf_spring_sec_roles` VALUES (1,'admin','ROLE_USER','2012-07-17 16:57:49','2012-07-17 16:57:49'),(2,'admin','ROLE_ADMIN','2012-07-17 16:58:08','2012-07-17 16:58:08'),(3,'guest','ROLE_USER','2012-07-17 16:59:17','2012-07-17 16:59:17');
Only three steps are required for mapping our custom implementation. Enjoy!
Sir,thanks a lot for your tutorial.I followed this series one by one,but I got a NullPointerException from this tutorial while checking the remeberme check box,please advise.
Warning: #{loginMgmtBean.login}: java.lang.NullPointerException
javax.faces.FacesException: #{loginMgmtBean.login}: java.lang.NullPointerExcepti
on
at com.sun.faces.application.ActionListenerImpl.processAction(ActionList
enerImpl.java:118)
Sir, thanks a lot for your tutorial. I have tried custom
database example . but it shows
org.springframework.security.authentication.BadCredentialsException:
Bad credentials for all input please help me..
me too i’m getting this error, have you resolved this problem, please let me know how to resolve it