In this tutorials, I am going to show how to secure spring boot rest endpoints using Spring Boot in memory basic authentication.
Spring Boot In Memory Basic Authentication:
As part of this tutorials, I am going to create a simple spring boot rest service which provides 3 basic endpoints such as reading, creating and deleting Items and these 3 endpoints have to be secured.
Spring Boot In Memory Basic Authentication Example:
Here, I am going to create a 2 different roles ADMIN and USER.
The users which are having ADMIN role can be accessible to Create and Delete Items. The USER role can be accessible to reading Items.
Technologies Used:
- Spring Boot 2.0.5
- Spring Boot Security
- Java 8
- Maven
Application Structure:
Project Dependencies:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.onlinetutorialspoint</groupId>
<artifactId>SpringBoot-InMemory-Security-Example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>SpringBoot-InMemory-Security-Example</name>
<description>Spring Boot In Memory Basic Authentication Security</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Security Configuration.
Creating 2 users: chandra and admin using Spring Boot’s in-memory AuthenticationManagerBuilder and assigned roles with USER and ADMIN respectively.
package com.onlinetutorialspoint.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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;
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder managerBuilder) throws Exception{
managerBuilder.inMemoryAuthentication()
.withUser("chandra").password("{noop}1234").roles("USER").and()
.withUser("admin").password("{noop}admin123").roles("ADMIN");
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.httpBasic().and().authorizeRequests()
.antMatchers("/addItem","/delete").hasRole("ADMIN")
.antMatchers("/getAllItems").hasRole("USER")
.and().csrf().disable().headers().frameOptions().disable();
}
}
Creating Item Model
package com.onlinetutorialspoint.model;
import java.io.Serializable;
public class Item implements Serializable {
private Integer id;
private String name;
private String category;
public Item() {
}
public Item(Integer id, String name, String category) {
this.id = id;
this.name = name;
this.category = category;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
}
Creating Item Service
package com.onlinetutorialspoint.services;
import com.onlinetutorialspoint.model.Item;
import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Repository
public class ItemService {
public static List<Item> items;
static{
items = new ArrayList<>(Arrays.asList(new Item(1,"Spring Boot in Action","Books"),
new Item(2,"Java 8 in Action","Books"),
new Item(3,"Data Structures","Books")));
}
public List<Item> getAllItems(){
return items;
}
public void addItem(Item item){
items.add(item);
}
public void deleteItem(int id){
items.removeIf(i -> i.getId().equals(id));
}
}
Creating Item Controller
package com.onlinetutorialspoint.controller;
import com.onlinetutorialspoint.model.Item;
import com.onlinetutorialspoint.services.ItemService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.util.UriComponentsBuilder;
import java.util.List;
@RestController
public class ItemController {
@Autowired
ItemService itemService;
@RequestMapping("/getAllItems")
@ResponseBody
public ResponseEntity<List<Item>> getAllItems(){
List<Item> items = itemService.getAllItems();
return new ResponseEntity<List<Item>>(items, HttpStatus.OK);
}
@PostMapping(value = "/addItem",consumes = {"application/json"},produces = {"application/json"})
@ResponseBody
public ResponseEntity<Item> addItem(@RequestBody Item item,UriComponentsBuilder builder){
itemService.addItem(item);
HttpHeaders headers = new HttpHeaders();
headers.setLocation(builder.path("/addItem/{id}").buildAndExpand(item.getId()).toUri());
return new ResponseEntity<Item>(headers, HttpStatus.CREATED);
}
@DeleteMapping("/delete/{id}")
@ResponseBody
public ResponseEntity<Void> deleteItem(@PathVariable int id){
itemService.deleteItem(id);
return new ResponseEntity<Void>(HttpStatus.ACCEPTED);
}
}
Main class:
package com.onlinetutorialspoint;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Run the application:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.0.5.RELEASE)
2018-10-21 13:00:44.551 INFO 6856 --- [ main] com.onlinetutorialspoint.Application : Starting Application on DESKTOP-RN4SMHT with PID 6856 (E:\work\SpringBoot-InMemory-Security-Example\target\classes started by Lenovo in E:\work\SpringBoot-InMemory-Security-Example)
2018-10-21 13:00:44.559 INFO 6856 --- [ main] com.onlinetutorialspoint.Application : No active profile set, falling back to default profiles: default
....
....
Access the application:
Reading allItems with valid user credentials.
Reading allItems with invalid user credentials.
Deleting Item with admin user.
Deleting an Item with an unknown user.
References:
Happy Learning 🙂