Spring 3 Security – Custom Login Form with Remember Me

This tutorial will demonstrate the following:

  1. Login with a custom login form (rather than the spring security default)
  2. Implement a remember me function
  3. Distinguish between being logged in via ‘Remember-Me’ versus Actually logged in

This tutorial follows on directly from the ‘Hello Spring Security‘ tutorial.

Recall from the previous tutorial that spring security configurations were used which resulted in a default login page.

 

Security configuration for custom login form with ‘Remember-Me’

Here is the modified version which specifies the page containing the login form:

  •  j_spring_security_check is the default login credentials processing facility.
  • /login is the login page containing the login form with the remember-me facility
  • j_spring_security_logout is the default logout processing facility.
  • The ‘logout-success-url’ is set to the home page ‘/
  • The remember me key is myAppKey. This is the name of the cookie created whereby the user is “remembered”. It will expire after 864000 seconds (10 days).

Custom Login Form

The login form looks like this:

  •  Note the name of the form variables:
  • j_username, j_password, _spring_security_remember_me
  • These are the required names which spring understands.

isAuthenticated() vs isFullyAuthenticated()

isAuthenticated() is true when logged in via the remember-me cookie.

isFullyAuthenticated() (and isAuthenticated()) is true when logged in via the login-form.

Example, in an eCommerce application isAuthenticated() may not be good enough for financial transactions, isfullyAuthenticated() would be more suitable to ensure the user was in fact the intended user rather than another user of the computer automatically logged-in from the remember-me cookie.

Use as so the the JSP’s

 

Use as so in the @Controllers

Note:

To enable the use of @PreAuthorise the following must be set in the spring-security.xml configuration.

….where pre-post-annotations=”enabled” is key.

 

Conclusion

This tutorial has built on the introductory spring security with Netbeans tutorial  here.

Using a custom login form for a spring security application has been demonstrated.

Adding a remember-me facility to the form has been demonstrated.

Logged in via the remember-me cookie versus logged in via the login form has been demonstrated.

Distinguishing between isAuthenticated() and isFullyAuthenticated() has been demonstrated  within the JSP and within the @Controller context

To set up this project and try out these features for yourself, please download the code from the previous tutorial and modify as described in this tutorial.

 

Comments always welcome….

 

 

  • Ranjan Sai

    can you provide the full code, because i unable to do it, Do you have any example remember me using persistance cookie mechanism using any db

  • Umar Farooq

    Thanks for this post.

    I tried the same mechanism But it throws the following exception

    Problem is due to the addition of the line

    org.springframework.web.context.ContextLoader ERROR Context initialization failed

    org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘org.springframework.security.filterChains’: Cannot resolve reference to bean ‘org.springframework.security.web.DefaultSecurityFilterChain#0′ while setting bean property ‘sourceList’ with key [0]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘org.springframework.security.web.DefaultSecurityFilterChain#0′: Cannot create inner bean ‘(inner bean)’ of type [org.springframework.security.web.authentication.logout.LogoutFilter] while setting constructor argument with key [1]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘(inner bean)#8′: Cannot resolve reference to bean ‘org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices#0′ while setting constructor argument with key [1]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices#0′: Cannot create inner bean ‘(inner bean)’ while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘(inner bean)#9′: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [org.springframework.security.core.userdetails.UserDetailsService org.springframework.security.config.http.UserDetailsServiceFactoryBean.cachingUserDetailsService(java.lang.String)] threw exception; nested exception is org.springframework.context.ApplicationContextException: No UserDetailsService registered.

    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:329)

    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:107)

    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveManagedList(BeanDefinitionValueResolver.java:354)

    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:154)

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1360)

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1118)

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517)

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)

    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)

    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)

    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)

    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)

    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:587)

    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:925)

    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:472)

    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:383)

    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:283)

    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:111)

    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4791)

    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5285)

    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)

    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)

    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)

    at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)

    at java.util.concurrent.FutureTask.run(Unknown Source)

    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)

    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)

    at java.lang.Thread.run(Unknown Source)

    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘org.springframework.security.web.DefaultSecurityFilterChain#0′: Cannot create inner bean ‘(inner bean)’ of type [org.springframework.security.web.authentication.logout.LogoutFilter] while setting constructor argument with key [1]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘(inner bean)#8′: Cannot resolve reference to bean ‘org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices#0′ while setting constructor argument with key [1]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices#0′: Cannot create inner bean ‘(inner bean)’ while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘(inner bean)#9′: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [org.springframework.security.core.userdetails.UserDetailsService org.springframework.security.config.http.UserDetailsServiceFactoryBean.cachingUserDetailsService(java.lang.String)] threw exception; nested exception is org.springframework.context.ApplicationContextException: No UserDetailsService registered.

    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:282)

    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:126)

    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveManagedList(BeanDefinitionValueResolver.java:354)

    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:154)

    at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:616)

    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:148)

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1035)

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:939)

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:485)

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)

    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)

    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)

    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)

    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)

    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:323)

    … 27 more

    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘(inner bean)#8′: Cannot resolve reference to bean ‘org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices#0′ while setting constructor argument with key [1]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices#0′: Cannot create inner bean ‘(inner bean)’ while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘(inner bean)#9′: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [org.springframework.security.core.userdetails.UserDetailsService org.springframework.security.config.http.UserDetailsServiceFactoryBean.cachingUserDetailsService(java.lang.String)] threw exception; nested exception is org.springframework.context.ApplicationContextException: No UserDetailsService registered.

    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:329)

    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:107)

    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveManagedList(BeanDefinitionValueResolver.java:354)

    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:154)

    at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:616)

    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:148)

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1035)

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:939)

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:485)

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)

    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:271)

    … 41 more

    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices#0′: Cannot create inner bean ‘(inner bean)’ while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘(inner bean)#9′: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [org.springframework.security.core.userdetails.UserDetailsService org.springframework.security.config.http.UserDetailsServiceFactoryBean.cachingUserDetailsService(java.lang.String)] threw exception; nested exception is org.springframework.context.ApplicationContextException: No UserDetailsService registered.

    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:282)

    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:126)

    at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:630)

    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:148)

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1035)

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:939)

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:485)

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)

    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)

    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)

    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)

    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)

    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:323)

    … 51 more

    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘(inner bean)#9′: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [org.springframework.security.core.userdetails.UserDetailsService org.springframework.security.config.http.UserDetailsServiceFactoryBean.cachingUserDetailsService(java.lang.String)] threw exception; nested exception is org.springframework.context.ApplicationContextException: No UserDetailsService registered.

    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:581)

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1015)

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:911)

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:485)

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)

    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:271)

    … 63 more

    Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [org.springframework.security.core.userdetails.UserDetailsService org.springframework.security.config.http.UserDetailsServiceFactoryBean.cachingUserDetailsService(java.lang.String)] threw exception; nested exception is org.springframework.context.ApplicationContextException: No UserDetailsService registered.

    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:181)

    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:570)

    … 68 more

    Caused by: org.springframework.context.ApplicationContextException: No UserDetailsService registered.

    at org.springframework.security.config.http.UserDetailsServiceFactoryBean.getUserDetailsService(UserDetailsServiceFactoryBean.java:99)

    at org.springframework.security.config.http.UserDetailsServiceFactoryBean.cachingUserDetailsService(UserDetailsServiceFactoryBean.java:39)

    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)

    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

    at java.lang.reflect.Method.invoke(Unknown Source)

    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:160)

    … 69 more

  • James Hake
  • Patrick Niemann

    Hey.

    Thanks for the tutorial…

    I followed it so far, and everything works…
    But now i want to read the user informations out of a database with Hibernate.

    Do you have a advice how to do that?

    Greetings
    Patrick