Background
Required Software
Technologies, Languages, and Frameworks
Project Structure
How to Run
H2 In Memory Database
I've changed the structure of this application around a few times now, but the goals of it have pretty much stayed the same.
The purpose of this project was to build a single page application built using Spring Boot and ReactJS SPA that has authentication and authorization through JWTs. It consists of a login page, a users page, and a teams page. If logged in as adminUser the teams and users pages will show controls for adding, editing, and deleting users and teams respectively. If logged in as activeUser this controls won't be present. This is to demonstrate permissions. Backend security prevents adding, editing, and deleting by a non-admin user.
Some of my goals in this project were to:
- Create an organized and scalable project structure for a Spring Boot application and React SPA
- Web security consisting of a form login, JSON Web Token, and user roles
- Session management and expiration. The use receives a warning their session is about to expire
- Through backend unit testing
- Provide Swagger API documentation
- Demonstrate a path to production
- Tokens have a 15-minute expiration. This can be altered with the spat.jwt-token-duration property.
- Refresh tokens have a 2-hour expiration. This can be altered with the spat.refresh-token-duration property.
- The JWT signing key can be set with the spat.jwt-signing-key property.
- The monitorSession method in autApi.js utilizes these defaults.
- On page load the application will try to use a refresh token which is stored in an HTTP only cookie to login.
- If a valid refresh token cookie exists, the application automatically logs the user and stores a JWT token in local storage. This token will be used for all application requests.
- If login fails through the refresh token, the application directs the user to login with their username and password.
- The application will update a last activity value in local storage after each successful request the user makes to the server.
- The application monitors the user's session every minute. If will request a new token from the refresh token cookie when it will expire less than two minutes. In addition, if the user has been inactive for more than token duration (15 minutes), they will be logged out.
- Java 11 (may be Java 8 compatible out of box or require some changes)
- Node.js
- Java 11
- Maven 3.6.3
- Spring Boot 2
- Spring Security that utilizes JSON Web Tokens
- Spring Data JPA. Hibernate does the data creation in this implementation, but custom scripts or Liquibase is also an option.
- H2 in memory database. This can easily be swapped out for another database.
- SpringDoc Open API for Swagger API documentation (https://github.com/springdoc/springdoc-openapi)
- JUnit 5
- React using Create React App (https://reactjs.org/docs/create-a-new-react-app.html)
- Reactstrap for Bootstrap 4 React Components (https://reactstrap.github.io/)
- React Font Awesome for icons (https://github.com/danawoodman/react-fontawesome)
- Formik for forms with ReactJS (https://jaredpalmer.com/formik/)
The project is a multi module Maven project consisting of two modules:
- spat-react-client - A React JS application using Create React App
- spat-services - Spring Boot REST service project
Each project can be imported into your preferred IDE. The steps below are how to run and build from the command line.
- Navigate to spat-react-client folder in console
- Do
npm install
- Do
npm run start
This will open a browser window at http://localhost:3000.
- Navigate to spat-services folder in console
- Run
mvnw spring-boot:run
. The will install dependencies and run the application.
At this point the service is running on http://localhost:10000
With spat-react-client and spat-services now running you should be able to login as
activeAdmin/password
or activeUser/password
.
Attempting to login as any of the following will fail with a reason given:
- credentialsExpiredUser
- disabledExpiredUser
- expiredExpiredUser
- lockedUser
These users can be updated inside the application.
- Navigate to spat-react-client folder in console
- Do
npm run build
- Transfer the assets in spat-react-client/build to your hosting solution
- Navigate to
spat-services
folder in console - Run
mvnw clean package
to run test and create a jar file - This will create a
target
folder that contains aspat-services.jar
. - Run
java -jar target/spat-service.jar
to run the jar file. You can choose to run the jar in Docker if you wish. - The following properties can be set using Spring's
application.properties
:- spat.cors-allowed-origins - what origins to allow. Default is to allow any.
- spat.jwt-signing-key - the signing key used for JWTs. In a production application you would not want to commit this, but rather load it from something like an environment variable.
- spat.jwt-token-duration - the duration of a JWT token. Must be less than the refresh token duration.
- spat.refresh-token-duration - the duration of a JWT refresh token.
The application uses the H2 in memory database. On startup, DatabaseLoad.java always re-creates the database.
There is a web console to the database that can be accessed by going to http://localhost:10000/h2-console and changing the JDBC URL to jdbc:h2:mem:spat.
Swagger documentation can be viewed when the spat-services application is running by going to http://localhost:10000/swagger-ui.html.