Languages
[Edit]
EN

Spring Boot 2 - simple custom authentication example using JPA and MySQL database

3 points
Created by:
Creg
9600

In this article, we would like to show how to create a simple web application with custom authentication using Spring Boot 2, JPA, and MySQL database.

Notes:

In the below example:

  1. to generate construstors, getters and setters automatically Lombok pre-procesor was used
    (check request, response and entity classes),
  2. to generate query methods automatically and query database Spring Data JPA was used
    (check UsersRepository interface).

Final effect:

Simple authentication example using Spring Boot 2, JPA, and MySQL database.
Simple authentication example using Spring Boot 2, JPA, and MySQL database.

Project structure:

 

DemoApplication.java file:

package com.example.demo;

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

@SpringBootApplication
public class DemoApplication {

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

 

AuthenticationController.java file:

package com.example.demo;

import com.example.demo.requests.UserLoginRequest;
import com.example.demo.requests.UserRegisterRequest;
import com.example.demo.responses.UserActionResponse;
import com.example.demo.responses.UserCheckResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import javax.servlet.http.HttpServletRequest;

@Controller
public class AuthenticationController {

    @Autowired
    private AuthenticationService authenticationService;

    @PostMapping("/api/user/check")
    public ResponseEntity<UserCheckResponse> checkUser(HttpServletRequest request) {
        return ResponseEntity.ok(this.authenticationService.checkUser(request));
    }

    @PostMapping("/api/user/login")
    public ResponseEntity<UserActionResponse> loginUser(HttpServletRequest request, @RequestBody UserLoginRequest data) {
        return ResponseEntity.ok(this.authenticationService.loginUser(request, data));
    }

    @PostMapping("/api/user/logout")
    public ResponseEntity<UserActionResponse> logoutUser(HttpServletRequest request) {
        return ResponseEntity.ok(this.authenticationService.logoutUser(request));
    }

    @PostMapping("/api/user/register")
    public ResponseEntity<UserActionResponse> registerUser(@RequestBody UserRegisterRequest data) {
        return ResponseEntity.ok(this.authenticationService.registerUser(data));
    }
}

 

AuthenticationService.java file:

package com.example.demo;

import com.example.demo.entities.UserEntity;
import com.example.demo.repositories.UsersRepository;
import com.example.demo.requests.UserLoginRequest;
import com.example.demo.requests.UserRegisterRequest;
import com.example.demo.responses.UserActionResponse;
import com.example.demo.responses.UserCheckResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Optional;

@Service
public class AuthenticationService {

    @Autowired
    private UsersRepository usersRepository;

    public boolean isUserLogged(HttpSession session) {
        Long loggedUserId = this.getLoggedUserId(session);
        return loggedUserId != null;
    }

    public boolean isUserLogged(HttpServletRequest request) {
        return this.isUserLogged(request.getSession());
    }

    public Long getLoggedUserId(HttpSession session) {
        return (Long) session.getAttribute("LOGGED_USER_ID");
    }

    public Long getLoggedUserId(HttpServletRequest request) {
        return this.getLoggedUserId(request.getSession());
    }

    public UserCheckResponse checkUser(HttpServletRequest request) {
        Long loggedUserId = this.getLoggedUserId(request);
        if (loggedUserId == null) {
            return new UserCheckResponse(false, "Currently, You are not logged in.", null);
        }
        Optional<UserEntity> userOptional = this.usersRepository.findById(loggedUserId);
        if (userOptional.isPresent()) {
            UserEntity userEntity = userOptional.get();
            return new UserCheckResponse(true, "Currently, You are logged in.", userEntity);
        } else {
            return new UserCheckResponse(false, "Logged in user doesn't exists.", null);
        }
    }

    public UserActionResponse loginUser(HttpServletRequest request, UserLoginRequest data) {
        HttpSession session = request.getSession();
        if (this.isUserLogged(session)) {
            return new UserActionResponse(false, "Login operation failed (You are already logged in).");
        }
        Optional<UserEntity> userOptional = this.usersRepository.findByUsernameAndPassword(data.getUsername(), data.getPassword());
        if (userOptional.isPresent()) {
            UserEntity userEntity = userOptional.get();
            session.setAttribute("LOGGED_USER_ID", userEntity.getId());
            return new UserActionResponse(true, "Login operation succeed.");
        }
        return new UserActionResponse(false, "Login operation failed (Incorrect user credentials).");
    }

    public UserActionResponse logoutUser(HttpServletRequest request) {
        HttpSession session = request.getSession();
        if (this.isUserLogged(session)) {
            session.removeAttribute("LOGGED_USER_ID");
            return new UserActionResponse(true, "Logout operation succeed.");
        }
        return new UserActionResponse(false, "Logout operation failed (Currently, You are not logged in).");
    }

    public UserActionResponse registerUser(UserRegisterRequest data) {
        UserEntity userEntity = new UserEntity(null, data.getUsername(), data.getPassword(), data.getEmail());
        try {
            this.usersRepository.save(userEntity);
            return new UserActionResponse(true, "Register operation succeed.");
        } catch (Throwable ex) {
            if (ex instanceof DataIntegrityViolationException) {
                return new UserActionResponse(false, "Register operation failed (username or email is used already by someone).");
            }
            return new UserActionResponse(false, "Register operation failed.");
        }
    }
}

 

repositories/UsersRepository.java file:

package com.example.demo.repositories;

import com.example.demo.entities.UserEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.Optional;

@Repository
public interface UsersRepository extends JpaRepository<UserEntity, Long> {

    Optional<UserEntity> findByUsernameAndPassword(String username, String password);
}

entities/UserEntity.java file:

package com.example.demo.entities;

import lombok.Getter;
import lombok.Setter;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;

import javax.persistence.*;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "users")
public class UserEntity {

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

    @Column(name = "username", nullable = false, unique = true)
    private String username;

    @Column(name = "password", nullable = false)
    private String password;

    @Column(name = "email", nullable = false, unique = true)
    private String email;
}

 

requests/UserLoginRequest.java file:

package com.example.demo.requests;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class UserLoginRequest {

    private String username;
    private String password;
}

requests/UserRegisterRequest.java file:

package com.example.demo.requests;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class UserRegisterRequest {
				
	private String username;
	private String password;
	private String email;
}

 

responses/UserActionResponse.java file:

package com.example.demo.responses;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class UserActionResponse {

	private boolean success;
	private String message;
}

responses/UserCheckResponse.java file:

package com.example.demo.responses;

import com.example.demo.entities.UserEntity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class UserCheckResponse {

	private boolean success;
	private String message;

	private UserEntity user;
}

 

resources/static/index.html file:

<!doctype html>
<html>
<head>
  <style>

    th {
        padding: 6px;
    }

    td {
        padding: 6px;
        border: 1px solid silver;
    }

  </style>
</head>
<body>
  <button onclick="checkUser()">Check user</button>
  <br /><br />
  <table>
    <tr>
      <th>Username</th>
      <th>Password</th>
      <th>E-mail</th>
      <th colspan="2"></th>
    </tr>
    <tr>
      <td>admin</td>
      <td>admin</td>
      <td>admin@email.com</td>
      <td><button onclick="loginUser('admin', 'admin')">Login</button></td>
      <td><button onclick="registerUser('admin', 'admin', 'admin@email.com')">Register</button></td>
    </tr>
    <tr>
      <td>user</td>
      <td>user</td>
      <td>user@email.com</td>
      <td><button onclick="loginUser('user', 'user')">Login</button></td>
      <td><button onclick="registerUser('user', 'user', 'user@email.com')">Register</button></td>
    </tr>
  </table>
  <br />
  <button onclick="logoutUser()">Logout user</button>
  <script>

      // Reusable logic:

      const sendData = async (requestUrl, requestData) => {
          const config = {
              method: 'POST',
              headers: {
                  'Accept': 'application/json',
                  'Content-Type': 'application/json'
              }
          };
          if (requestData) {
              config.body = JSON.stringify(requestData); // request body
          }
          const response = await fetch(requestUrl, config);
          return await response.json();
      };


      // Example actions:

      const checkUser = async () => {
          const responseData = await sendData('/api/user/check');
          alert(JSON.stringify(responseData, null, 4));
      };

      const loginUser = async (username, password) => {
          const requestData = {username, password};
          const responseData = await sendData('/api/user/login', requestData);
          alert(JSON.stringify(responseData, null, 4));
      };

      const logoutUser = async () => {
          const responseData = await sendData('/api/user/logout');
          alert(JSON.stringify(responseData, null, 4));
      };

      const registerUser = async (username, password, email) => {
          const requestData = {username, password, email};
          const responseData = await sendData('/api/user/register', requestData);
          alert(JSON.stringify(responseData, null, 4));
      };

  </script>
</body>
</html>

 

resources/application.properties file:

db.host=localhost
db.port=3306
db.name=demo_db

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://${db.host}:${db.port}/${db.name}?useUnicode=yes&characterEncoding=UTF-8&serverTimezone=UTC&character_set_server=utf8mb4
spring.datasource.username=root
spring.datasource.password=root

spring.jpa.hibernate.ddl-auto=update

Hint: to run database in the computer memory go to this snippet to see how to use H2 database.

 

pom.xml file:

<?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.6.5</version>
		<relativePath/>
	</parent>

	<name>demo</name>
	<description>Demo project for Spring Boot</description>

	<groupId>com.example</groupId>
	<artifactId>demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<properties>
		<java.version>11</java.version>
		<maven.compiler.source>${java.version}</maven.compiler.source>
		<maven.compiler.target>${java.version}</maven.compiler.target>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.22</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.18.24</version>
			<scope>provided</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.7.0</version>
				<configuration>
					<source>${maven.compiler.source}</source>
					<target>${maven.compiler.target}</target>
					<annotationProcessorPaths>
						<path>
							<groupId>org.projectlombok</groupId>
							<artifactId>lombok</artifactId>
							<version>1.18.24</version>
						</path>
					</annotationProcessorPaths>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

Hint: to run database in the computer memory go to this snippet to see how to use H2 database (in that case mysql-connector-java dependency can be removed from pom.xml file).

 

Database preparation

1. Database should be created using:

CREATE DATABASE `demo_db`

2. users table will be created or updated automatically by Spring Boot 2 Application
(configured by spring.jpa.hibernate.ddl-auto=update property).

 

See also

  1. Spring Boot 2 - using Lombok plugin with Maven project (in pom.xml file)

  2. Spring Boot 2 - CRUD example using JPA and MySQL database

Alternative titles

  1. Spring Boot 2 - simple own authentication example using JPA and MySQL database
Donate to Dirask
Our content is created by volunteers - like Wikipedia. If you think, the things we do are good, donate us. Thanks!
Join to our subscribers to be up to date with content, news and offers.
Native Advertising
🚀
Get your tech brand or product in front of software developers.
For more information Contact us
Dirask - we help you to
solve coding problems.
Ask question.

❤️💻 🙂

Join