Friday, 9 October 2020

How to Use Spring Security without UserDetailService in SpringBoot to Secure Rest Service End Point

Spring Security is a powerful and highly customizable authentication and access-control framework. 
It is the de-facto standard for securing Spring-based applications.

Spring provide  WebSecurityConfigurerAdapter configure the Spring Security. WebSecurityConfigurerAdapter class provides a configure(HttpSecurity http) method that contains the following default configuration.
 
The following classes enable Spring Web Security with in memory authentication with provided users details .

Directory Structure of Springboot project 
























Maven dependency to enable spring security .

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>



SecurityConfig.java

package in.jk.springbootapplication.configuration;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

/*
 * Enable Spring Web Security with in memory authentication without UserDetailsService (Without Database Authentication)
 */

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

protected void configure(HttpSecurity httpSecurity) throws Exception {

       httpSecurity.csrf().disable().authorizeRequests().antMatchers("/adminapi/employee/**")
.hasAnyRole("ADMIN", "USER")
                                .and().authorizeRequests().antMatchers("/adminapi/product/**")
.hasAnyRole("USER").and().formLogin();

}

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {

auth.inMemoryAuthentication()
                       .withUser("jk123").password("{noop}jk@123").roles("ADMIN", "USER")
                        .and().withUser("john").password("{noop}john").roles("USER");

}

}


Controller 

In this application controller class contain three type of URL one for user service to add user the service URL start with user and other two start with employee and product  protected with spring security . they require authentication access them .

AdminController.java

package in.jk.springbootapplication.controller;

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;
import in.jk.springbootapplication.request.EmployeeRequest;
import in.jk.springbootapplication.request.ProductRequest;
import in.jk.springbootapplication.request.UserRequest;
import in.jk.springbootapplication.response.Response;
import in.jk.springbootapplication.service.AdminService;

@RestController
@RequestMapping("/adminapi")
public class AdminController {

@Autowired
private AdminService adminService;


@RequestMapping(value = "/user/findUserById/{userId}", method = RequestMethod.GET)
public Response findUserById(@PathVariable Integer userId) {
return adminService.findUserById(userId);

}

@RequestMapping(value = "/user/addUser", method = RequestMethod.POST)
public Response addProduct(@RequestBody UserRequest user) {
return adminService.addUser(user);

}

@RequestMapping(value = "/employee/findEmployeeById/{employeeId}",
         method = RequestMethod.GET)
public Response findEmployeeById(@PathVariable Integer employeeId) {

return adminService.findEmployeeById(employeeId);

}

@RequestMapping(value = "/employee/addEmployee", method = RequestMethod.POST)
public Response addEmployee(@RequestBody EmployeeRequest employee) {

return adminService.addEmployee(employee);

}

@RequestMapping(value = "/product/findProductById/{productId}", 
         method = RequestMethod.GET)
public Response findProductById(@PathVariable Integer productId) {

return adminService.findProductById(productId);

}

@RequestMapping(value = "/product/addProduct", method = RequestMethod.POST)
public Response addProduct(@RequestBody ProductRequest product) {
            return adminService.addProduct(product);

}

}

EmployeeRequest.java

package in.jk.springbootapplication.request;

public class EmployeeRequest {
private int employeeId;
private String name;
private String company;
        //Getters and Setters 
@Override
public String toString() {
return "Employee [employeeId=" + employeeId + ", name=" + name + ", 
                comapny=" + company + "]";
}
}

ProductRequest.java

package in.jk.springbootapplication.request;

public class ProductRequest {
private int productId;
private String productName;
private int price;
private String company;
       //Getters and Setters
@Override
public String toString() {
return "ProductRequest [productId=" + productId + ", productName=" + 
                productName + ", price=" + price
+ ", company=" + company + "]";
}
}

UserRequest.java

package in.jk.springbootapplication.request;
public class UserRequest {
private Integer userId;
private String userName;
private String name;
private String password;
private String emailId;
private String  role;
       //Getters and Setters
@Override
public String toString() {
return "UserRequest [userId=" + userId + ", userName=" + userName + ", 
                name=" + name + ", password=" + password
+ ", emailId=" + emailId + ", role=" + role + "]";
}
}

Spring Security application entity classes 
Employee.java

package in.jk.springbootapplication.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

@Entity
@Table(name="springboot.employee")
@NamedQuery(name="findEmployeeByName",query = "FROM Employee employee where employee.name=:name")
public class Employee {

@Id
@Column(name="employee_id")
private Integer employeeId;
@Column(name="name")
private String name;
@Column(name="company")
private String company;

// Getters and Setters

@Override
public String toString() {
return "Employee [employeeId=" + employeeId + ", name=" + name + ",
       comapny=" + company + "]";
}
}

Product.java
package in.jk.springbootapplication.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="springboot_product")
public class Product {
@Id
@Column(name="product_id")
private int productId;
@Column(name="product_name")
private String productName;
@Column(name="price")
private int price;
@Column(name="company")
private String company;
        //Getters and Setters
@Override
public String toString() {
return "ProductRequest [productId=" + productId + ", productName=" +
               productName + ", price=" + price+ ", company=" + company + "]";
}

}

User.java

package in.jk.springbootapplication.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="springboot_user")
public class User {
@Id
@Column(name="user_id")
private Integer userId;
@Column(name="user_name")
private String userName;
@Column(name="name")
private String name;
@Column(name="password")
private String password;
@Column(name="email_id")
private String emailId;
@Column(name="role")
private String  role;
        //Getters and Setters
@Override
public String toString() {
return "UserRequest [userId=" + userId + ", userName=" + userName + ", 
                name=" + name + ", password=" + password
+ ", emailId=" + emailId + ", role=" + role + "]";
}
}

Spring Security application Repository classes 

EmployeeRepositry.java

package in.jk.springbootapplication.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import in.jk.springbootapplication.entity.Employee;

public interface EmployeeRepositry extends JpaRepository<Employee, Integer> {

}

ProductRepository.java

package in.jk.springbootapplication.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import in.jk.springbootapplication.entity.Product;

public interface ProductRepository  extends JpaRepository<Product, Integer>{
}

UserRepository.java

package in.jk.springbootapplication.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import in.jk.springbootapplication.entity.User;

public interface UserRepository extends JpaRepository<User, Integer> {
}

Spring Security Application class  to send response to user
Response.java

package in.jk.springbootapplication.response;

public class Response {
private Object responseData;
private String responseMessage;
private String responseCode;
public void setResponse(String responseCode,Object data, String responseMessage) {
this.responseCode=responseCode;
this.responseData =data;
this.responseMessage=responseMessage;
}
public Object getResponseData() {
return responseData;
}
public void setResponseData(Object responseData) {
this.responseData = responseData;
}
public String getResponseMessage() {
return responseMessage;
}
public void setResponseMessage(String responseMessage) {
this.responseMessage = responseMessage;
}
public String getResponseCode() {
return responseCode;
}
public void setResponseCode(String responseCode) {
this.responseCode = responseCode;
}
@Override
public String toString() {
return "Response [responseData=" + responseData + ", responseMessage=" + 
                responseMessage + ", responseCode="
+ responseCode + "]";
}

}


Service Interface and class of Spring Security Application 

package in.jk.springbootapplication.service;

import in.jk.springbootapplication.entity.User;
import in.jk.springbootapplication.request.EmployeeRequest;
import in.jk.springbootapplication.request.ProductRequest;
import in.jk.springbootapplication.request.UserRequest;
import in.jk.springbootapplication.response.Response;

public interface AdminService {

public Response findUserById(Integer userId);

public Response addUser(UserRequest user);

public Response findEmployeeById(Integer employeeId);

public Response addEmployee(EmployeeRequest employee);

public Response findProductById(Integer productId);

public Response addProduct(ProductRequest product);

}

AdminServiceImpl.java
 
package in.jk.springbootapplication.service.impl;

import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import in.jk.springbootapplication.entity.Employee;
import in.jk.springbootapplication.entity.Product;
import in.jk.springbootapplication.entity.User;
import in.jk.springbootapplication.repository.EmployeeRepositry;
import in.jk.springbootapplication.repository.ProductRepository;
import in.jk.springbootapplication.repository.UserRepository;
import in.jk.springbootapplication.request.EmployeeRequest;
import in.jk.springbootapplication.request.ProductRequest;
import in.jk.springbootapplication.request.UserRequest;
import in.jk.springbootapplication.response.Response;
import in.jk.springbootapplication.service.AdminService;

@Service
public class AdminServiceImpl implements AdminService {

@Autowired
private UserRepository userRepository;
@Autowired
private EmployeeRepositry employeeRepositry;
@Autowired
private ProductRepository productRepository;

@Override
public Response findUserById(Integer userId) {

Response response = null;
User entity = null;

response = new Response();
try {
Optional<User> user = userRepository.findById(userId);
if (user.isPresent()) {
entity = user.get();
response.setResponse("200", entity, "User Find Succussfully ");

} else {
response.setResponse("200", entity, "User Not Present ");

}

} catch (Exception e) {
response.setResponse("500", e.getMessage(), "Error in Finding User ");
}

return response;
}

@Override
public Response addUser(UserRequest userRequest) {

Response response = null;
User user = new User();
user.setUserId(userRequest.getUserId());
user.setName(userRequest.getName());
user.setUserName(userRequest.getUserName());
user.setEmailId(userRequest.getEmailId());
user.setRole(userRequest.getRole());

BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String password = passwordEncoder.encode(userRequest.getPassword());

user.setPassword(password);

response = new Response();
try {
userRepository.save(user);
response.setResponse("200", user, "User Added Succussfully ");
} catch (Exception e) {
response.setResponse("500", e.getMessage(), "Error in Adding User ");
}

return response;
}


@Override
public Response findEmployeeById(Integer employeeId) {

Response response = null;
Employee entity = null;

response = new Response();
try {
Optional<Employee> employee = employeeRepositry.findById(employeeId);
if (employee.isPresent()) {
entity = employee.get();
response.setResponse("200", entity, "Employee Find Succussfully ");

} else {
response.setResponse("200", entity, "Employee Not Present ");

}

} catch (Exception e) {
response.setResponse("500", null, "Error in Finding Employee ");
}

return response;
}

@Override
public Response addEmployee(EmployeeRequest employee) {
Response response = null;
Employee entity = new Employee();
entity.setEmployeeId(employee.getEmployeeId());
entity.setName(employee.getName());
entity.setCompany(employee.getCompany());

response = new Response();
try {
employeeRepositry.save(entity);
response.setResponse("200", entity, "Employee Added Succussfully ");
} catch (Exception e) {
response.setResponse("500", null, "Error in Adding Employee ");
}

return response;
}

@Override
public Response findProductById(Integer productId) {

Response response = null;
Product entity = null;

response = new Response();
try {
Optional<Product> product = productRepository.findById(productId);
if (product.isPresent()) {
entity = product.get();
response.setResponse("200", entity, "Product Find Succussfully ");

} else {
response.setResponse("200", entity, "Product Not Present ");

}

} catch (Exception e) {
response.setResponse("500", e.getMessage(), "Error in Finding Product ");
}

return response;
}

@Override
public Response addProduct(ProductRequest product) {

Response response = null;
Product entity = new Product();
entity.setProductId(product.getProductId());
entity.setProductName(product.getProductName());
entity.setPrice(product.getPrice());
entity.setCompany(product.getCompany());

response = new Response();
try {
productRepository.save(entity);
response.setResponse("200", entity, "Product Added Succussfully ");
} catch (Exception e) {
response.setResponse("500", e.getMessage(), "Error in Adding Product ");
}

return response;
}

}

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.0-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>in.jk</groupId>
<artifactId>springbootapplication</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springbootapplication</name>
<description>Demo project for Spring Boot</description>

<properties>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--  Jackson Dependency for json conversion -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>     
</dependency>

<!-- Swagger Dependency .. -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</pluginRepository>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>

</project>

Spring Security Swagger Config 
SwaggerConfig.java

package in.jk.springbootapplication.configuration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class SwaggerConfig {                                    
    @Bean
    public Docket api() { 
        return new Docket(DocumentationType.SPRING_WEB)  
          .select()                                  
          .apis(RequestHandlerSelectors.any())              
          .paths(PathSelectors.any())                          
          .build();                                           
    }
}

SpringbootApplication.java

package in.jk.springbootapplication;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringbootApplication {

public static void main(String[] args) {
SpringApplication.run(SpringbootApplication.class, args);
System.out.println("Spring Boot Application started .....");
}

}


How to test Spring Security application 

1. Right click on SpringbootApplication and start application open new Browser type following URL 

http://localhost:8080/swagger-ui.html#
You will see follwing service URL 






















User Service URL is not protected with spring security so it does not require authentication .
Now add one User with userId 1 by using Swagger URL using add user Post URL
Open new Browser type following URL for user Service with userId 1

http://localhost:8080/adminapi/user/findUserById/1







2 .Testing of Employee Service 

Employee Service is protected by Spring Security it require authentication 
for employee Service we have set follwoing username ,password and role
 
username = jk123
password = jk@123
role     = ADMIN

Open new Browser window and type follwing url

http://localhost:8080/adminapi/employee/findEmployeeById/10
after entering above URL it open a login form like bellow












After the entering username and password click on login button it authenticate use and gives following response .










So until we didn't added any employee in our application so go to Swagger UI and add one employee with employeeId 1 and then add following url 
http://localhost:8080/adminapi/employee/findEmployeeById/1
above URL gives Response with Employee Id 1








Note :- IF you try access product service URL which protect by other user details then it gives follwing response with Product Service URL

http://localhost:8080/adminapi/product/findProductById/1













3 .Testing of Product Service 

Product Service is protected by Spring Security it require authentication 
for Product Service we have set follwoing username ,password and role
 
username = john
password = john
role     = USER

Open new Browser window and type follwing url

http://localhost:8080/adminapi/product/findProductById/10
after entering above URL it open a login form like bellow














After the entering username and password click on login button it authenticate use and gives follwoing response .










So until we did'nt added any product in our application so go to Swagger UI and add one product with productId 1 and then add following url
 
http://localhost:8080/adminapi/product/findProductById/1
above URL gives Response with productId 1









Note :- IF you try access employee service URL which employee by other user details then 
it gives follwing response with Employee Service URL
http://localhost:8080/adminapi/employee/findEmployeeById/1







 





So this is how we can implement Spring securty in Springboot application .

please comment if you find any mistake .....




  



  
















No comments:

Post a Comment