In this article, let’s learn how to enable Spring Security REST Basic Authentication. We will be setting up the Spring Security using XML configuration. We will be building the Employee Management system where in which you will be able to Create an Employee, Get all the Employee / particular Employee details, Modify an existing Employee and Delete the Employee.
Based on the HTTP verbs, our REST API does the below
- Create Employee (POST) : Create a new Employee (/employee)
- Get Employee By Id (GET) : Get a Employee based on id (/employee/1)
- List of All Employees (GET) : Get all the Employees (/employees)
- Update Employee (PUT) : Update a Employee (/employee)
- Delete Employee (DELETE) : Delete a Employee (/employee/1)
Creating table
Create EMPLOYEE Table, simply Copy and Paste the following SQL query in the query editor to get the table created.
CREATE TABLE EMPLOYEE( ID int(10) NOT NULL, NAME varchar(50) NOT NULL, AGE int(10) NOT NULL, DEPT varchar(20) NOT NULL, PRIMARY KEY EMPLOYEE(ID)); INSERT INTO EMPLOYEE VALUES (1,'JIP1',10,'IT'); INSERT INTO EMPLOYEE VALUES (2,'JIP2',20,'IT'); INSERT INTO EMPLOYEE VALUES (3,'JIP3',30,'IT'); INSERT INTO EMPLOYEE VALUES (4,'JIP4',40,'IT');
Folder Structure:
- Create a simple Maven Project “SpringRestSecurity” and create a package for our source files “com.javainterviewpoint” under src/main/java
- Now add the following dependency in the 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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.javainterviewpoint</groupId> <artifactId>SpringRestSecurity</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>SpringSecurityTutorial Maven Webapp</name> <url>http://maven.apache.org</url> <properties> <spring.version>4.3.21.RELEASE</spring.version> <security.version>4.2.10.RELEASE</security.version> <jdk.version>1.8</jdk.version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</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>${security.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>${security.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>${security.version}</version> </dependency> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- MySQL Dependency --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.13</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.8.1</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.8.1</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.8.1</version> </dependency> </dependencies> <build> <finalName>SpringRestSecurity</finalName> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> <version>3.0</version> </plugin> </plugins> </build> </project>
- Create the Java class Employee.java, EmployeeDAO.java, EmployeeDAOImpl.java and EmployeeController.java under com.javainterviewpoint folder.
- Place the SpringConfig.xml and web.xml under the WEB-INF directory
Spring Security REST Basic Authentication
web.xml
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <display-name>Spring Rest Security</display-name> <servlet> <servlet-name>SpringConfig</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/SpringConfig.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>SpringConfig</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- Loads Spring Security configuration file --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/SpringConfig.xml</param-value> </context-param> <!-- Spring Security filter --> <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>
- The web.xml has everything about the application that a server needs to know, which is placed under the WEB-INF directory. It contains the name of the SpringConfiguration file when the DispatcherServlet is initialized the framework will try to load a configuration file “[servlet-name]-servlet.xml” under the WEB-INF directory.
- Spring Security depends on the Servlet filter, we will be using the filter “DelegatingFilterProxy” which filters and directs all the requests to pass through the Spring Security mechanism. (Note: The filter name should only be “springSecurityFilterChain” )
SpringConfig.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:security="http://www.springframework.org/schema/security" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <mvc:annotation-driven> </mvc:annotation-driven> <context:component-scan base-package="com.javainterviewpoint"> </context:component-scan> <!-- <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/Jsp/" /> <property name="suffix" value=".jsp" /> </bean> --> <!-- Database Configurations --> <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/mydb" /> <property name="username" value="root" /> <property name="password" value="root" /> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="employeeDAOImpl" class="com.javainterviewpoint.EmployeeDAOImpl"> <property name="jdbcTemplate" ref="jdbcTemplate" /> </bean> <!-- Spring Security Configuration --> <security:http auto-config="true" use-expressions="true"> <security:intercept-url pattern="/*" access="hasRole('ROLE_USER')"/> <security:csrf disabled="true"/> </security:http> <security:authentication-manager> <security:authentication-provider> <security:user-service> <security:user name="user" password="password" authorities="ROLE_USER"/> </security:user-service> </security:authentication-provider> </security:authentication-manager> </beans>
- The SpringConfig.xml is also placed under the WEB-INF directory.
- <context:component-scan> will let the Spring Container to search for all the annotation under the package “com.javainteriviewpoint”.
- <mvc:annotation-driven/> annotation will activate the @Controller, @RequestMapping, @Valid etc annotations.
- The <security:http> tag allows you to configure the Security Settings and access constraints for the web application. we have set the auto-config attribute as “true” this gives you the basic security configuration.
<security:http auto-config="true" use-expressions="true"> <security:intercept-url pattern="/*" access="hasRole('ROLE_USER')"/> <security:csrf disabled="true"/> </security:http>
- The <security:intercept-url> tag defines the pattern which will be matched against the URLs of the incoming requests, the access attribute validates the role which is required for accessing the URL. In our case all the incoming request will be validated, whether the user has the role ROLE_USER
- <security:authentication-manager> tag has authentication properties through which the user will have access to different url.
<security:authentication-manager> <security:authentication-provider> <security:user-service> <security:user name="user" password="password" authorities="ROLE_USER"/> </security:user-service> </security:authentication-provider> </security:authentication-manager>
- <security:authentication-provider> tag specifies type of authentication mechanism which will be used such as ldap, user, jdbc in our case it is user-service.
- <security:user> tag provides the username and password. For our application, we have used the username as “user” and Password as “password” and the authority as “ROLE_USER”
- DriverManagerDataSource – DriverManagerDataSource contains database related configurations such as driver class name, connection URL, username and password.
- JdbcTemplate – We will be referencing the dataSource id (DriverManagerDataSource ) to the property dataSource of the JdbcTemplate class.
- EmployeeDAOImpl – We will be referencing the jdbcTemplate id to the property jdbcTemplate of the EmployeeDAOImpl class.
EmployeeDAO.java
package com.javainterviewpoint; import java.util.List; public interface EmployeeDAO { public void saveEmployee(Employee employee); public Employee getEmployeeById(Long id); public void updateEmployee(Employee employee); public void deleteEmployee(Long id); public List<Employee> getAllEmployees(); }
EmployeeDAOImpl.java
package com.javainterviewpoint; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.jdbc.core.RowMapper; public class EmployeeDAOImpl implements EmployeeDAO { private JdbcTemplate jdbcTemplate; // JdbcTemplate setter public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } // Saving a new Employee public void saveEmployee(Employee employee) { String sql = "insert into Employee values(?,?,?,?)"; jdbcTemplate.update(sql, new Object[] { employee.getId(),employee.getName(), employee.getAge(), employee.getDept() }); } // Getting a particular Employee public Employee getEmployeeById(Long id) { String sql = "select * from Employee where id=?"; Employee employee = (Employee) jdbcTemplate.queryForObject(sql, new Object[] { id }, new RowMapper() { @Override public Employee mapRow(ResultSet rs, int rowNum) throws SQLException { Employee employee = new Employee(); employee.setId(rs.getLong(1)); employee.setName(rs.getString(2)); employee.setAge(rs.getLong(3)); employee.setDept(rs.getString(4)); return employee; } }); return employee; } // Getting all the Employees public List<Employee> getAllEmployees() { String sql = "select * from Employee"; List<Employee> employeeList = jdbcTemplate.query(sql, new ResultSetExtractor<List<Employee>>() { @Override public List<Employee> extractData(ResultSet rs) throws SQLException, DataAccessException { List<Employee> list = new ArrayList<Employee>(); while (rs.next()) { Employee employee = new Employee(); employee.setId(rs.getLong(1)); employee.setName(rs.getString(2)); employee.setAge(rs.getLong(3)); employee.setDept(rs.getString(4)); list.add(employee); } return list; } }); return employeeList; } // Updating a particular Employee public void updateEmployee(Employee employee) { String sql = "update Employee set age =?, dept=?,name=? where id=?"; jdbcTemplate.update(sql, new Object[] { employee.getAge(), employee.getDept(), employee.getName(), employee.getId() }); } // Deletion of a particular Employee public void deleteEmployee(Long id) { String sql = "delete from employee where id=?"; jdbcTemplate.update(sql, new Object[] { id }); } }
EmployeeController.java
package com.javainterviewpoint; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @RestController public class EmployeeController { @Autowired private EmployeeDAOImpl employeeDAO; @RequestMapping(value = "/employee",method=RequestMethod.POST) public void saveEmployee(@RequestBody Employee employee) { employeeDAO.saveEmployee(employee); } @RequestMapping(value = "/employee/{id}",method=RequestMethod.GET) public Employee getEmployeeById(@PathVariable("id") Long id) { Employee employee = employeeDAO.getEmployeeById(id); return employee; } @RequestMapping(value = "/employees",method=RequestMethod.GET) public List<Employee> listEmployees() { List<Employee> employeeList = employeeDAO.getAllEmployees(); return employeeList; } @RequestMapping(value = "/employee",method=RequestMethod.PUT) public void update(@RequestBody Employee employee) { employeeDAO.updateEmployee(employee); } @RequestMapping(value = "/employee/{id}",method=RequestMethod.DELETE) public void deleteEmployee(@PathVariable("id") Long id) { employeeDAO.deleteEmployee(id); } }
Employee.java
Employee class is a simple POJO consisting getters and setters of Employee properties id, name, age, dept.
package com.javainterviewpoint; import java.io.Serializable; public class Employee implements Serializable { private static final long serialVersionUID = 2401397786933204698L; private Long id; private String name; private Long age; private String dept; public Employee() { super(); } public Employee(Long id, String name, Long age, String dept) { super(); this.id = id; this.name = name; this.age = age; this.dept = dept; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Long getAge() { return age; } public void setAge(Long age) { this.age = age; } public String getDept() { return dept; } public void setDept(String dept) { this.dept = dept; } @Override public String toString() { return "Employee [id=" + id + ", name=" + name + ", age=" + age + ", dept=" + dept + "]"; } }
Output
In POSTMAN, select GET method and give the url as “http://localhost:8080/SpringRestSecurity/employees”. In the Authorization tab select the Type as “Basic Auth” and key in the invalid username /password. You will be getting 401 Unauthorized error
Now pass the valid username and password (user/password)
Leave a Reply