Introduction:

In today’s digital age, securing web applications is paramount. Spring Security is a powerful and highly customizable authentication and access-control framework for Java applications. When paired with ReactJS, you can create a seamless and secure login experience for your users. This article will guide you through the process of integrating a Spring Security login page with a ReactJS front end. This is a step-by-step article to create the React Login Page and make it work with Spring Security.

1. Create a React Application

First, we’ll create a new React application using the Create React App. Navigate into your dev-workspace and create the react app as shown below:

npx create-react-app amazing-login-page
cd amazing-login-page

2. Design the Login Page

Open the src/App.js file and replace the existing code with the following:

src/App.js
import React, { useState } from 'react';
import './App.css';

function App() {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    // Here, you can make an AJAX request to your Spring Boot backend for authentication
    console.log('Username:', username);
    console.log('Password:', password);
  };

  return (
    <div className="login-container">
      <h1>Amazing Login</h1>
      <form onSubmit={handleSubmit}>
        <div className="form-group">
          <label htmlFor="username">Username</label>
          <input
            type="text"
            id="username"
            value={username}
            onChange={(e) => setUsername(e.target.value)}
            required
          />
        </div>
        <div className="form-group">
          <label htmlFor="password">Password</label>
          <input
            type="password"
            id="password"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
            required
          />
        </div>
        <button type="submit">Login</button>
      </form>
    </div>
  );
}

export default App;

Next, create a new file src/App.css and add the following styles:

src/App.css
.login-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
  background-color: #f5f5f5;
}

h1 {
  font-size: 2.5rem;
  margin-bottom: 2rem;
  color: #333;
  text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
}

form {
  display: flex;
  flex-direction: column;
  align-items: center;
  background-color: #fff;
  padding: 2rem;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.form-group {
  margin-bottom: 1rem;
  width: 100%;
}

label {
  font-weight: bold;
  color: #555;
}

input {
  width: 100%;
  padding: 0.5rem;
  border: 1px solid #ccc;
  border-radius: 4px;
  font-size: 1rem;
}

button {
  padding: 0.5rem 1rem;
  background-color: #007bff;
  color: #fff;
  border: none;
  border-radius: 4px;
  font-size: 1rem;
  cursor: pointer;
  transition: background-color 0.3s ease;
}

button:hover {
  background-color: #0056b3;
}

This code creates a clean and modern login page with a centered form and styling for the input fields and buttons.

3. Configure Spring Security

In your Spring Boot application, locate the SecurityConfig class and modify it to use the React login page:

Java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests()
                 // Allow access to the login page without authentication
                .requestMatchers("/login/**", "/resources/**").permitAll() 
                // Require authentication for all other requests
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login") // Specify the path to your React login page
                .permitAll() // Allow access to the login page without authentication
                .and()
            .logout()
                .permitAll(); // Allow access to the logout endpoint without authentication

        return http.build();
    }

    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails user =
            User.withDefaultPasswordEncoder()
                .username("user1")
                .password("password1")
                .roles("USER")
                .build();

        return new InMemoryUserDetailsManager(user);
    }
}

In this configuration, we specify the path /login as the login page for Spring Security. This path should match the URL where your React application is served.

Explanation:

  1. We define a SecurityFilterChain bean and configure the HTTP security rules inside the filterChain method.
  2. The authorizeHttpRequests() method is used to configure the access rules for different URL patterns.
    • .requestMatchers("/login/**").permitAll() allows access to the /login path and its subpaths without authentication. This is necessary to ensure that the React login page can be accessed by unauthenticated users.
    • .anyRequest().authenticated() requires authentication for all other requests.
  3. The formLogin() method is used to configure the form-based authentication.
    • .loginPage("/login") specifies the path to the React login page.
    • .permitAll() allows access to the login page without authentication.
  4. The logout() method is used to configure the logout behavior, and .permitAll() allows access to the logout endpoint without authentication.
  5. The userDetailsService() method creates an in-memory user with the username “user1” and password “password1” with the “USER” role.

With this configuration, the React login page at /login can be accessed without authentication, and the in-memory user “user1” with password “password1” can be used for authentication purposes.

4. Create the Controller

Create a controller to handle the login page request.

Java
@Controller
public class LoginController {

    @GetMapping("/login")
    public String login() {
        return "login";
    }
}

5. Serve the React Application

To serve the React application, you can use a separate web server or integrate it with your Spring Boot application. Here’s an example of how to integrate it using the spring-boot-starter-webpack dependency:

  1. Add the following dependency to your pom.xml:
XML
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webpack</artifactId>
</dependency>
  1. Create a new file frontend/webpack.config.js with the following content:
frontend/webpack.config.js
const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, '../src/main/resources/static'),
    filename: 'bundle.js'
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env', '@babel/preset-react']
          }
        }
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      }
    ]
  },
  resolve: {
    extensions: ['.js', '.jsx']
  }
};
  1. Update your pom.xml to include the webpack-maven-plugin and configure it:
pom.xml
<plugin>
    <groupId>com.github.eirslett</groupId>
    <artifactId>frontend-maven-plugin</artifactId>
    <version>1.15.0</version>
    <configuration>
        <workingDirectory>frontend</workingDirectory>
        <installDirectory>target</installDirectory>
    </configuration>
    <executions>
        <execution>
            <id>install node and npm</id>
            <goals>
                <goal>install-node-and-npm</goal>
            </goals>
            <configuration>
                <nodeVersion>v16.15.1</nodeVersion>
            </configuration>
        </execution>
        <execution>
            <id>npm install</id>
            <goals>
                <goal>npm</goal>
            </goals>
            <configuration>
                <arguments>install</arguments>
            </configuration>
        </execution>
        <execution>
            <id>webpack build</id>
            <goals>
                <goal>webpack</goal>
            </goals>
        </execution>
    </executions>
</plugin>

This configuration will build your React application and copy the bundled JavaScript file to the src/main/resources/static directory, which is served by Spring Boot.

With these changes, your Spring Boot application will serve the React login page at the /login path, and Spring Security will use it for authentication.

Note: This is just one way to integrate a React application with Spring Boot. There are other approaches, such as using a separate web server for the frontend or building the React application separately and serving it from Spring Boot’s static resources directory.

Conclusion:

By following these steps, you’ve successfully integrated Spring Security with a ReactJS login page, creating a secure and responsive authentication system. This setup not only ensures robust security for your application but also offers a seamless user experience. Leveraging the strengths of Spring Security for back-end authentication and ReactJS for front-end interface development, you can build modern, secure, and user-friendly web applications.

Stay updated with the latest best practices in security and front-end development to keep your application secure and efficient. Happy coding!

By |Last Updated: May 26th, 2024|Categories: Spring Security|