In this tutorial we will see how to use database to perform the form-based login authentication in Spring Security.
Example
Create Database Tables
We are using MySQL as databasecreate database for users to authenticate.
CREATE DATABASE maheshdb;
In database maheshdb create 2 tables users , user_roles
to store user details and user role details, one to many relationship,
one user can contains many roles.
you are allow to add extra columns for extra functionality. In additional, the table name and column name are not fixed, you can rename to whatever name.
CREATE TABLE maheshdb.`users` ( `USER_ID` INT(10) UNSIGNED NOT NULL, `USERNAME` VARCHAR(45) NOT NULL, `PASSWORD` VARCHAR(45) NOT NULL, `ENABLED` tinyint(1) NOT NULL, PRIMARY KEY (`USER_ID`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE maheshdb.`user_roles` ( `USER_ROLE_ID` INT(10) UNSIGNED NOT NULL, `USER_ID` INT(10) UNSIGNED NOT NULL, `AUTHORITY` VARCHAR(45) NOT NULL, PRIMARY KEY (`USER_ROLE_ID`), KEY `FK_user_roles` (`USER_ID`), CONSTRAINT `FK_user_roles` FOREIGN KEY (`USER_ID`) REFERENCES `users` (`USER_ID`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Insert data in tables for to test application.
INSERT INTO maheshdb.users (USER_ID, USERNAME,PASSWORD, ENABLED) VALUES (100, 'mahesh', '24251', TRUE); INSERT INTO maheshdb.user_roles (USER_ROLE_ID, USER_ID,AUTHORITY) VALUES (1, 100, 'ROLE_USER');
Here is the content for pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.mahesh.spring</groupId> <artifactId>SpringSecurity</artifactId> <packaging>war</packaging> <version>1.0-SNAPSHOT</version> <name>SpringSecurity Maven Webapp</name> <url>http://maven.apache.org</url> <properties> <spring.version>3.0.5.RELEASE</spring.version> </properties> <dependencies> <!-- Spring 3 dependencies --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <!-- Spring Security --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>${spring.version}</version> </dependency> <!-- jstl --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- MySQL database driver --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.9</version> </dependency> </dependencies> <build> <finalName>SpringSecurity</finalName> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> </plugins> </build> </project>
Here is the content for web.xml
web.xml should contain DelegatingFilterProxy definition with specified filtername.
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <display-name>Spring MVC Application</display-name> <!-- Spring MVC --> <servlet> <servlet-name>mvc-dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>mvc-dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/mvc-dispatcher-servlet.xml, /WEB-INF/spring-database.xml, /WEB-INF/spring-security.xml </param-value> </context-param> <!-- Spring Security --> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
Here is the content for Spring Database spring-database.xml
Create a data source bean, and connect to database via Spring JDBC.
<beans xmlns="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"> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/maheshdb" /> <property name="username" value="root" /> <property name="password" value="root" /> </bean> </beans>
Here is the content for Spring Security spring-security.xml
use “jdbc-user-service” tag, and define your query to get the data from database.
<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"> <intercept-url pattern="/welcome*" access="ROLE_USER" /> <form-login login-page="/login" default-target-url="/welcome" authentication-failure-url="/loginfailed" /> <logout logout-success-url="/logout" /> </http> <authentication-manager> <authentication-provider> <jdbc-user-service data-source-ref="dataSource" users-by-username-query=" select username,password, enabled from users where USERNAME=?" authorities-by-username-query=" select u.username, ur.authority from users u, user_roles ur where u.user_id = ur.user_id and u.username =? " /> </authentication-provider> </authentication-manager> </beans:beans>
Here is the content for Spring configuration file for mvc mvc-dispatcher-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" 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/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:component-scan base-package="com.mahesh.common.controller" /> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix"> <value>/WEB-INF/pages/</value> </property> <property name="suffix"> <value>.jsp</value> </property> </bean> <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basenames"> <list> <value>mymessages</value> </list> </property> </bean> </beans>
Here is the content for mymessages.properties
AbstractUserDetailsAuthenticationProvider.badCredentials=Invalid username or password
Here is the content for LoginController.java
package com.mahesh.common.controller; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.User; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller public class LoginController { @RequestMapping(value="/welcome", method = RequestMethod.GET) public String printWelcome(ModelMap model) { User user = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal(); String name = user.getUsername(); model.addAttribute("username", name); model.addAttribute("message", "Spring Security login + database example"); return "hello"; } @RequestMapping(value="/login", method = RequestMethod.GET) public String login(ModelMap model) { return "login"; } @RequestMapping(value="/loginfailed", method = RequestMethod.GET) public String loginerror(ModelMap model) { model.addAttribute("error", "true"); return "login"; } @RequestMapping(value="/logout", method = RequestMethod.GET) public String logout(ModelMap model) { return "login"; } }
Here is the content for login.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <html> <head> <title>Login Page</title> <style> .errorblock { color: #ff0000; background-color: #ffEEEE; border: 3px solid #ff0000; padding: 8px; margin: 16px; } </style> </head> <body onload='document.f.j_username.focus();'> <h3>Login with Username and Password (Authentication with Database)</h3> <c:if test="${not empty error}"> <div class="errorblock"> Your login attempt was not successful, try again.<br /> Caused : ${sessionScope["SPRING_SECURITY_LAST_EXCEPTION"].message} </div> </c:if> <form name='f' action="<c:url value='j_spring_security_check' />" method='POST'> <table> <tr> <td>User:</td> <td><input type='text' name='j_username' value=''> </td> </tr> <tr> <td>Password:</td> <td><input type='password' name='j_password' /> </td> </tr> <tr> <td colspan='2'><input name="submit" type="submit" value="submit" /> </td> </tr> <tr> <td colspan='2'><input name="reset" type="reset" /> </td> </tr> </table> </form> </body> </html>
Here is the content for hello.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <html> <body> <h3>Message : ${message}</h3> <h3>Username : ${username}</h3> <a href="<c:url value="/j_spring_security_logout" />" > Logout</a> </body> </html>
Steps to create war file and deploy it in web/Application server.
1. execute mvn clean install command on root directory.
2. SpringSecurity.war file will be created in target folder.
3. copy it to deployment folder of server and start server.
Below are the Screen shots
Great work. I did not use the all tutorial but found within it exactly what I was looking for. Thank you.
ReplyDelete