Build a Rest API with Spring Boot using MySQL and JPA

Build a Rest API with Spring Boot using MySQL and JPA

In that case, I found a very clean and elegant framework called Spring Boot to build a back end.

In that case, I found a very clean and elegant framework called Spring Boot to build a back end.

Previously, in JavaScript development, I used:

  1. Mongoose — an ORM (Object Relational Mapping) for Mongo DB
  2. Sequelize — an ORM for MySQL

For Java-related development, there are lot of ORM’s like Hibernate, JPA (Java Persistence API) & Java Object Oriented Querying.

I choose to build with JPA which is traditionally used in Java applications.

It was very interesting, and took about one week to finish as I had to learn Spring Boot (There are a lot of annotations “@” and other cool kinds of stuff to learn), JPA, and Hibernate along the way.

All this magic is mostly done by the annotations (“@” symbol) used in Spring Boot.

Creating a Spring Boot Maven Project

Let’s create a Spring Boot Maven Project Application using this link.

Maven” is a project management tool used to manage dependency management. It’s just like Node Package Manager (NPM) in the JS development environment.

We have package.json in NodeJS for dependency management and pom.xml in Spring Boot for dependency management.

In Group, write whatever the name you want. Usually, the domain name of the organization is written right to left.

For example our domain name is www.javaAPI.com, so the group name could be com.javaAPI.www

Then in the Artifact type the name of the folder you want.

On the right side, add the following dependencies:

  1. Mongoose — an ORM (Object Relational Mapping) for Mongo DB
  2. Sequelize — an ORM for MySQL

Then click “Generate Project”. You will find a rar file — extract it. Then open that folder in your favorite IDE.

Click on the com.rest.API and you will find an ApiApplication.java file as follows:

package com.rest.API;

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

@SpringBootApplication
public class ApiApplication {

public static void main(String[] args) {
      SpringApplication.run(ApiApplication.class, args);
   }
}

This code is enough to start your server. Normally spring boot runs on localhost:8080.

Type in your terminal as follows:

mvn spring-boot:run
See your localhost running in the web browser at port 8080. It looks blank as we haven’t done anything yet.

Let’s explore the files and their tags

If you have a look at the pom.xml file you may notice that the dependencies you put in when creating the application in Spring Initialize like MySQL, JPA, and Web will be inside a tag.

The starter and tester dependencies are the core for creating the Spring Boot Application to serve on the server.

Now, let’s move to APIApplication.java which is the main file.

package com.rest.API;

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

@SpringBootApplication
public class ApiApplication {

public static void main(String[] args) {
      SpringApplication.run(ApiApplication.class, args);
   }
}

Here the name of the package is in the first line of the code. Using that package name, you can import any class, method, or instances in another package file.

After that, two modules are imported from “org.springframework.boot” package.

  1. Mongoose — an ORM (Object Relational Mapping) for Mongo DB
  2. Sequelize — an ORM for MySQL

Since Spring boot is the latest application developing framework of Spring, it needs the packages of Spring Application as well as its specific packages.

After that @SpringBootApplication Annotation is used. This Annotation consists of annotation which is used in Spring:

  1. Mongoose — an ORM (Object Relational Mapping) for Mongo DB
  2. Sequelize — an ORM for MySQL

These are the annotations used to start the Spring Boot Application to run on a server.

Here is an article I have written about Annotation & their uses in Java.

Let’s create Model for our data

Let’s create a Model class to save, retrieve, update and delete the details of a book.

For that, I have to create a new package named model and inside that creating a Book.java class to put my code.

package com.rest.API.model;

import javax.persistence.*;
import javax.validation.constraints.NotBlank;

@Entity
@Table(name = "books")

public class Book {
    @Id
    @GeneratedValue
    private Long id;

@NotBlank
    private String book_name;

@NotBlank
    private String author_name;

@NotBlank
    private String isbn;

public Book(){
        super();
    }

public Book(Long id, String book_name, String author_name, String isbn) {
        super();
        this.id = id;
        this.book_name = book_name;
        this.author_name = author_name;
        this.isbn=isbn;
    }

public Long getId() {
        return id;
    }

public void setId(Long id) {
        this.id = id;
    }

public String getBook_name() {
        return book_name;
    }

public void setBook_name(String book_name) {
        this.book_name = book_name;
    }

public String getAuthor_name() {
        return author_name;
    }

public void setAuthor_name(String author_name) {
        this.author_name = author_name;
    }

public String getIsbn() {
        return isbn;
    }

public void setIsbn(String isbn) {
        this.isbn = isbn;
    }

}

Here I’m using JPA (Java Persistence API) which is a collection of classes and methods to continuously store data into a database.

@Entity — used to denote that this class is going to be an Entity in the database.

@Table — which takes some values like the name you are going to name your table

**@Id **— denotes that the id is the primary key / identifying key for this table

@NotBlank — is used to say that these attributes should not be blank.

Other than that there is an empty constructor which has a super method to satisfy the JPA customs. Getter and setter methods are usually in a POJO class (Plain old Java object).

Creating the Repository

Next, we are going to create a repository package to deal with database management in Java.

Create an Interface called BookRepository.java inside the repository package.

package com.rest.API.repository;

import com.rest.API.model.Book;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface BookRepository extends JpaRepository<Book, Long> {

}

I have imported the JpaRepository package to use that repository in the BookRepository interface by connecting my most recently coded Book model to do CRUD operations.

There are already built-in methods in those repositories to do CRUD operations.

Eg:

.findAll() - to get All datas
.save()    - to save the got Data
.delete()  - to delete the data

Inside the <> tag we are taking the Model name we are going to use and the Primary key’s datatype.

@Repository: Annotation used to Indicate the DAO (Data Access Object) component in the persistence layer.

It tells the compiler that the interface is going to use the Repository to do database activities.

Creating Controller and Exception Handling

Create a new package called controller, andinside that create a BookController.java file which contains the endpoints.

package com.rest.API.controller;

import com.rest.API.exception.BookNotFoundException;
import com.rest.API.model.Book;
import com.rest.API.repository.BookRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.http.ResponseEntity;
import javax.validation.Valid;
import java.util.List;

@RestController
public class BookController {

@Autowired
    BookRepository bookRepository;

// Get All Notes
    @GetMapping("/books")
    public List<Book> getAllNotes() {
        return bookRepository.findAll();
    }

// Create a new Note
    @PostMapping("/books")
    public Book createNote(@Valid @RequestBody Book book) {
        return bookRepository.save(book);
    }

// Get a Single Note
    @GetMapping("/books/{id}")
    public Book getNoteById(@PathVariable(value = "id") Long bookId) throws BookNotFoundException {
        return bookRepository.findById(bookId)
                .orElseThrow(() -> new BookNotFoundException(bookId));
    }

// Update a Note
    @PutMapping("/books/{id}")
    public Book updateNote(@PathVariable(value = "id") Long bookId,
                           @Valid @RequestBody Book bookDetails) throws BookNotFoundException {

Book book = bookRepository.findById(bookId)
                .orElseThrow(() -> new BookNotFoundException(bookId));

book.setBook_name(bookDetails.getBook_name());
        book.setAuthor_name(bookDetails.getAuthor_name());
        book.setIsbn(bookDetails.getIsbn());

Book updatedBook = bookRepository.save(book);

return updatedBook;
    }

// Delete a Note
    @DeleteMapping("/books/{id}")
    public ResponseEntity<?> deleteBook(@PathVariable(value = "id") Long bookId) throws BookNotFoundException {
        Book book = bookRepository.findById(bookId)
                .orElseThrow(() -> new BookNotFoundException(bookId));

bookRepository.delete(book);

return ResponseEntity.ok().build();
    }
}

The first imported package is for the Book Not Found exception (for which we are going to create a file in a bit).

Explanation of Annotations we used here:

  1. Mongoose — an ORM (Object Relational Mapping) for Mongo DB
  2. Sequelize — an ORM for MySQL

So what is Domain Object…?

It simply says that Domain Object == Business Object.

They are usually represented by entities and value objects related to the endpoint we are giving to get the data from the database.

  1. Autowired: This annotation is used to wire the bean classes automatically.

For that, you need to know about “What is a bean Class…?

Basically, a Java Bean Class is a simple class which encapsulates many objects into it.

This is an article I wrote on Java Bean Classes.

The following are the Mapping Annotations for the endpoints to perform CRUD Operations.

  1. GetMapping: This is an interface which contains the path of the endpoint to perform a Get method. This GetMapping interface uses the RequestMapping interface which can have the “path, value, params, headers” method to perform the Get method in earlier Spring versions.

Now it’s simplified by using GetMapping.

  1. PostMapping: This is an interface which contains the path of the endpoint to perform the Post method.

  2. PutMapping: This is an interface which contains the path of the endpoint to perform the Put method to Update.

  3. DeleteMapping: This is an interface which contains the path of the endpoint to perform the Delete method.

In the final lines, you probably noticed the “ResponseEntity” keyword.

What is that…??

It’s a Java class which inherits HttpEntity class to manipulate the HTTP Responses. Whether the request of the connection is “OK” or if there are any problems, throw an exception from the HttpEntity class.

orElseThrow(): This is a method found in the Optional class in Java8 which was introduced to handle Exceptions. The optional class provides various utility methods to check the presence or absence of an object, which helps to deal with NullPointerException.

orElseThrow is a method that Returns value if present, otherwise invokes an exception.

Creating a NotFoundException if there is no such book_id

As orElseThrow method throws a NotFound Exception. The following is the Exception Handling part. Create a BookNotFoundException.java file inside exception package.

package com.rest.API.exception;

public class BookNotFoundException extends Exception {

private long book_id;

public BookNotFoundException(long book_id) {
        super(String.format("Book is not found with id : '%s'", book_id));
        }

}

The created class extends the Superclass of Exception. In the constructor, I’m passing the book_id & prints the exception.

So, that’s it…

We have finished the REST API part. Now you can build the app (which was explained in Part 1) and do some Testings with Postman.

Connecting with MySql Database

Inside the application.properties of your resources folder, add the following:

## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url = jdbc:mysql://localhost:3306/library
spring.datasource.username = root //normally put your MySQL username 
spring.datasource.password = YOUR_MYSQL_PASSWORD

## Hibernate Properties
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect

# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = update

That’s it.

We have built a basic REST API in Spring Boot. Congrats!

If anything is wrong or need to be corrected, please let me know in the comments section.

Happy Coding!

How to build a CRUD REST API using Spring Boot 2, JPA/Hibernate and MySQL

How to build a CRUD REST API using Spring Boot 2, JPA/Hibernate and MySQL

In this article we will learn how to develop a CRUD RESTFul API with Spring Boot 2 + JPA/Hibernate and MySQL as database.

In this article we will learn how to develop a CRUD RESTFul API with Spring Boot 2 + JPA/Hibernate and MySQL as database.

The end goal of these articles is to deploy this application on Oracle Cloud. But first, we will develop and test the application using a local database.

Before we get started, here is a list of what we need to complete this tutorial:

The API we will develop

We will create a Contact Resource exposing three services using RESTFul URIs and HTTP methods:

  • Retrieve all contacts - @GetMapping(“/contacts)
  • Get details of specific contact - @GetMapping(“/contacts/{id}”)
  • Delete a contact - @DeleteMapping(“/contacts/{id}”)
  • Create a new contact - @PostMapping(“/contacts)
  • Update existing contact details - @PutMapping(“/contacts/{id}”)

Creating the REST Spring Boot application

To create the Spring Boot application, we’ll use start.spring.io, which will provide us some bootstrap code (main class and pom.xml files). We need the WebJPALombok and MySQL packages for this example:

Look at the From the above diagram, we have specified the following details:

Generate: Maven Project
Java Version: 1.8 (Default)
Spring Boot:2.1.1
Group: com.loiane
Artifact: spring-cloud-mysql
Dependencies: Web, JPA, Lombok, MySQL

After entering all details, click on Generate Project button, download the zip file, extract its contents to your workspace and open it in your favorite IDE.

Project Structure

The following screenshot shows the structure of the project we will create.

Creating the model (JPA Entity)

The first class we will create is the JPA Entity. We will create a class Contact with a primary key id:

The model is the same as part 1 of this article series, but we will specify the how the ID will be auto generated because we are no longer using H2 database.
@AllArgsConstructor
@NoArgsConstructor
@Data
@Entity
public class Contact {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;
private String email;
private String phone;
}

The following annotations are from project Lombok and help us keep our classes (specially model/POJO) cleaner without the getters and setters:

  • AllArgsConstructor: automatically creates a class construtor with all arguments (properties).
  • NoArgsConstructor: automatically creates an empty class construtor with all arguments (properties).
  • Data: creates toStringequalshashCodegetters and setters.

Creating the JPA Repository

To easily access the methods to manipulate the Contact table, we just need to create an interface that extends JpaRepository passing the class that represents our model and the type of the primary key as generic arguments:

@Repository
public interface ContactRepository
extends JpaRepository<Contact, Long> { }

The JpaRepository interface provides a simple and easy way to access all the CRUD operations.

Creating the Controller

To access our data, we will also need a Controller.

@RestController
@RequestMapping({"/contacts"})
public class ContactController {

private ContactRepository repository;

ContactController(ContactRepository contactRepository) {
this.repository = contactRepository;
}

// CRUD methods here
}

The @RestController annotation contains the @Controller and @ResponseBody annotations. The @Controller annotation represents a class with endpoints and the @ResponseBody indicates indicates a method return value should be bound to the web response body (according to the documentation).

The @RequestMapping("/contacts") indicates that the url of the API in this controller will start with /contacts, so we will be able to access http://localhost:8080/contacts as our endpoint.

Please note we are not using the @Autowired annotation to automatically inject the repository. We are using dependency injection through the constructor as it is a recommended best practice.

As this is a simple example, we are not creating a Service class to iterate with the repository. Creating a service layer is a good practice as we can keep our controller class clean and add any required business logic to the service instead.

Let’s take a look at each method next.

Retrieve All Contacts (GET /contacts)
@GetMapping
public List findAll(){
return repository.findAll();
}

The findAll method is going to retrieve all the records from the database (select * from contact).

As this is a RESTful API, we can omit the @RequestMapping(value="/contacts", method=RequestMethod.GET) and simply use @GetMapping.

Retrieve a Contact by ID (GET /contacts/{id})
@GetMapping(path = {"/{id}"})
public ResponseEntity<Contact> findById(@PathVariable long id){
return repository.findById(id)
.map(record -> ResponseEntity.ok().body(record))
.orElse(ResponseEntity.notFound().build());
}

The @PathVariable annotation binds the method parameter id with the path variable {id}.

we will go to the database and will try to retrieve the contact (select * from contact where id = ?). If a contact is found, we return it (HTTP 200 - OK), else, we return HTTP 404 -Not Found.

Create a new Contact (POST /contacts)
@PostMapping
public Contact create(@RequestBody Contact contact){
return repository.save(contact);
}

The @RequestBody annotation indicates a method parameter should be bound to the body of the web request. This means the method expects the following content from que request (in JSON format):

{
"name": "Java",
"email": "[email protected]",
"phone": "(111) 111-1111"
}

Spring will automatically parse the request and create a variable of type Contact with its contents. Then, it will save it. The id of the contact will be null, therefore the save method will perform an insert into the Contact table.

Update a Contact (PUT /contacts)
@PutMapping(value="/{id}")
public ResponseEntity<Contact> update(@PathVariable("id") long id,
@RequestBody Contact contact){
return repository.findById(id)
.map(record -> {
record.setName(contact.getName());
record.setEmail(contact.getEmail());
record.setPhone(contact.getPhone());
Contact updated = repository.save(record);
return ResponseEntity.ok().body(updated);
}).orElse(ResponseEntity.notFound().build());
}

In order to update a contact, we need to inform its ID in the path variable. We also need to pass the updated contact.

Next, we will try to find the contact to be updated. If the contact is found, we update the values from the record from the database with the values passed as parameter to the method and save it. In this case, as the record exists, an update statement will performed in the contact table. We also return the updated contact. In case the contact is not found, it returns HTTP 404.

Remove a Contact (DELETE /contacts/{id})
@DeleteMapping(path ={"/{id}"})
public ResponseEntity<?> delete(@PathVariable("id") long id) {
return repository.findById(id)
.map(record -> {
repository.deleteById(id);
return ResponseEntity.ok().build();
}).orElse(ResponseEntity.notFound().build());
}

To remove a contact, we first need to retrieve it from the database. In case it is found, we delete it passing its ID and return HTTP 200 to indicate the deletion was performed successfully. In case the contact is not found, we return HTTP 404.

Initializing the MySQL database

As a last step, we are going to insert a few records in the MySQL contact table by declaring a Bean that returns a CommandLineRunner - this step is optional in case you already using an existing database/table.

@SpringBootApplication
public class SpringCloudMysqlApplication {

public static void main(String[] args) {
	SpringApplication.run(SpringCloudMysqlApplication.class, args);
}

@Bean
CommandLineRunner init(ContactRepository repository) {
	return args -&gt; {
		repository.deleteAll();
		LongStream.range(1, 11)
				.mapToObj(i -&gt; {
					Contact c = new Contact();
					c.setName("Contact " + i);
					c.setEmail("contact" + i + "@email.com");
					c.setPhone("(111) 111-1111");
					return c;
				})
				.map(v -&gt; repository.save(v))
				.forEach(System.out::println);
	};
}

}

Configuring MySQL Database

In order for our code to be able to connect to a MySQL database, we also need to inform the connection details. We are going to add these details inside src/maind/resources/application.properties:

## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url=jdbc:mysql://localhost:3306/mydatabase?useSSL=false
spring.datasource.username=root
spring.datasource.password=root

The SQL dialect makes Hibernate generate better SQL for the chosen database

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect

In case you want Hibernate to automatically generate the table in the database, we can use the following configuration as well:

# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto=update

Although this makes easier during the development, this is not recommended in production. For production, you might want to create a functional ID (user/password) that can perform all CRUD operations in the tables (DML (Data Manipulation Language) commands), but cannot perform any DDL (Data Definition Language) commands (Create, Drop, Alter tables, and so on).

To create the contact table, we can use the following SQL script:

CREATE TABLE mydatabase.contact (
id INT NOT NULL,
name VARCHAR(255) NULL,
email VARCHAR(255) NULL,
phone VARCHAR(45) NULL,
PRIMARY KEY (id));

ALTER TABLE mydatabase.contact
CHANGE COLUMN id id INT(11) NOT NULL AUTO_INCREMENT ,
ADD UNIQUE INDEX id_UNIQUE (id ASC);

Testing the APIs

We can test the API using Postman. If you use Visual Studio Code, you can also use the REST Client extension.

File for testing using the REST Client extension is also included in the source code

Conclusion

In this article, we developed and tested a CRUD API connecting to a real database locally. 

I hope this tutorial will surely help and you if you liked this tutorial, please consider sharing it with others

Spring REST API Security Tutorial: Using OAuth2 + MySQL

Spring REST API Security Tutorial: Using OAuth2 + MySQL

Let's secure our Spring REST API with OAuth2 and MySQL. REST easy knowing your APIs are secure after this tutorial.

Let’s secure our Spring REST API with OAuth2 and MySQL. We will store user credentials in the MySQL database, and client credentials will be stored in the in-memory database. Every client has its own unique client ID.

To secure our REST API, we will have to do the following things:

  • Configure Spring Security and the database.

  • Configure the authorization server and resource server.

  • Get an access token and a refresh token.

  • Get a protected Resource (REST API) using an access token.

Before we start, let's look at some basic concepts related to Spring Security OAuth2.

You may also like: Spring Security Tutorial: Simple Authentication with Spring Boot.

OAuth2 Roles

Resource Owner

A resource owner is a person (like an end-user) in an application that owns the service or security policy.

Resource Server

This is the resource server hosting the protected resource or service.

Client Application

The client application is the application requesting access to resources stored on the resource server. The client application also obtains authorization from the resource owner.

Authorization Server

The authorization server is the server authorizing the client app to access the resources of the resource owner.

Application

Let's start to secure our REST API endpoints.

First, we need to enable Spring Security to add the security feature in the application. To configure and enable Spring Security, the @EnableWebSecurity annotation is used.

By using @EnableGlobalMethodSecurity, we can easily secure our methods with Java configurations. Global method security will activate  @PreFilter@PostFilter , @PreAuthorize, and the @PostAuthorize  annotations if we want to use them.

@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
  @Autowired
  UserDetailsServiceImpl userDetailsService;
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) 
      .and().authorizeRequests().antMatchers("/oauth/token")
      .permitAll().anyRequest().authenticated();
  }
  @Bean
  public DaoAuthenticationProvider authenticationProvider() {
    DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
    provider.setPasswordEncoder( bCryptPasswordEncoder() );
    provider.setUserDetailsService(userDetailsService);
    return provider;
  }
  @Bean
  public BCryptPasswordEncoder bCryptPasswordEncoder() {
    return new BCryptPasswordEncoder();
  }
  @Override
  @Bean
  public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
  }
  @Autowired
  public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(authenticationProvider());
  }
}

Note:

  • Here, WebSecurityConfigurerAdapter  is used to customize security implementation.

  • Endpoint /OAuth/tpken is used to request a token (access or refresh).

  • We inject a custom implementation of UserDetailsService in order to retrieve user details from the database.

  • We use the defined BCryptPasswordEncoder bean for password encoding.

Now, we need to configure the authorization server. The @EnableAuhtorizationServer  annotation enables an authorization server. AuthorizationServerConfigurerAdapter  implements the  AuthorizationServerConfigurer, which provides all the necessary methods to configure an Authorization server. It also contains information about registered clients and possible access to scopes and grant types.

@Configuration
@EnableAuthorizationServer
public class OAuthConfiguration extends AuthorizationServerConfigurerAdapter {
  @Autowired
  @Qualifier("authenticationManagerBean")
  private AuthenticationManager authenticationManager;
  @Autowired
  UserDetailsService userDetailsService;
  @Override
  public void configure(final AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
    oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
  }
  @Override
  public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    clients.inMemory()
      .withClient("fooClientId").secret("secret")
      .authorizedGrantTypes("password", "authorization_code", "refresh_token").scopes("read","write")
      .autoApprove(true);
  }
  @Override
  public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    endpoints.tokenStore(tokenStore()).authenticationManager(authenticationManager).accessTokenConverter(defaultAccessTokenConverter())
      .userDetailsService(userDetailsService);
  }
  @Bean
  public TokenStore tokenStore(){
    return new JwtTokenStore(defaultAccessTokenConverter());
  }
  @Bean
  public JwtAccessTokenConverter defaultAccessTokenConverter() {
    JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
    converter.setSigningKey("123");
    return converter;
  }
}

Notes on the above configuration:

  • Registers a client with client-id ‘fooClientId’ and password ‘ secret’ and the roles and scope they are allowed.

  • Specifies authorized grant types (password, authorization_code, refresh_token).

  • Specifies the JwtTokenStore to store tokens.

Next, we need to configure the resource server. The @EnableResourceServer  annotation, applied on OAuth2 Resource Servers, enables a Spring Security filter that authenticates requests using an incoming OAuth2 token.

The class ResourceServerConfigurerAdapter implements the ResourceServerConfigure,  providing methods to adjust the access rules and paths that are protected by OAuth2 security.

@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
    private static final String RESOURCE_ID = "resource-server-rest-api";
    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources.resourceId(RESOURCE_ID);
    }
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.antMatcher("/**").authorizeRequests().anyRequest().authenticated();
    }
}

Next, we need to update the application.properties to configure the MySQL database. Create the user_management schema in MySQL and add the user table to store user credentials with roles.

spring.datasource.url = jdbc:mysql://localhost:3306/user_management
spring.datasource.username = root
spring.datasource.password = root

# Hibernate ddl auto (create, create-drop, update)
spring.jpa.hibernate.ddl-auto = update

# Naming strategy
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy

# Use spring.jpa.properties.* for Hibernate native properties (the prefix is
# stripped before adding them to the entity manager)

# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
server.port = 8080
Test Application

To access any secured REST API endpoint, first, we will have to get the access token. To get the access token, we will need to add an authorization header with client credentials and add the request body with user credentials in postman.

After receiving the access token and refresh token, we can access any secured REST API endpoints using access token. When the access token expired, the refresh token is used to get a new access token.

I have attached some of postmen request responses

getToken

getUser

addUser

You can refer to the whole project on GitHub.

Thank for reading. I hope this tutorial will surely help and you if you liked this tutorial, please consider sharing it with others

Originally published on dzone.com

Related Articles