Spring Security – Backend

Below are the steps to implement the backend system of this application.

Step 1: We can create the spring project using Spring STS IDE on creating the project add the below dependencies into our spring project.

Dependencies

  • Spring Web
  • Spring Web Security
  • Spring data for mongodb
  • Spring Dev Tools
  • Lombok

Once completed the creation of the spring project and create the required package also then the file structure looks like below image:

File structure


Step 2: Open the application.properities file and put the below code into that file. This code can be configuration of the database and spring security permissions to allow the react app request into this project.

application.properties:

server.port=8081
spring.data.mongodb.uri=mongodb://localhost:27017/userData
spring.application.name=LOGIN-SERVICE
# Session Management Configuration
spring.security.filter.chain.content-negotiation.parameter-strategy=ignore
spring.security.filter.chain.any-request.authorized=permitAll
spring.security.filter.chain.request-matcher.path.pattern=/api/**
spring.security.filter.chain.request-matcher.path.authenticated=true
# CSRF Configuration
spring.security.csrf.disabled=true
# CORS Configuration
spring.security.cors.configurationSource.allowedOrigins=http://localhost:3000
spring.security.cors.configurationSource.allowedMethods=*
spring.security.cors.configurationSource.allowedHeaders=*
spring.security.cors.configurationSource.allowCredentials=true
spring.security.cors.configurationSource.exposedHeaders=Authorization
spring.security.cors.configurationSource.maxAge=3600

Step 3: Create the usermodel package and in that package create the Java class and it named as the User for the user data handling into the project.

Go to the src > in.mahesh.tasks > usermodel > User and put the below code:

Java




package in.mahesh.tasks.usermodel;
  
import java.util.List;
  
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
  
import com.fasterxml.jackson.annotation.JsonProperty;
  
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
  
@Document(collection = "user")
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User {
  
    @Id
    private String id;
    private String fullName;
    private String email;
    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    private String password;
    private String role = "ROLE_CUSTOMER";
    private String mobile;
      
  
      
      
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String get_id() {
        return id;
    }
    public void set_id(String id) {
        this.id = id;
    }
    public String getFullName() {
        return fullName;
    }
    public void setFullName(String fullName) {
        this.fullName = fullName;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String getRole() {
        return role;
    }
    public void setRole(String role) {
        this.role = role;
    }
    public String getMobile() {
        return mobile;
    }
    public void setMobile(String mobile) {
        this.mobile = mobile;
    }
      
}


Step 4: Create the repository package and in that package create the Java interface and it named as the UserRepository for the user data can save into the database.

Go to the src > in.mahesh.tasks > repository> UserRepository and put the below code:

Java




package in.mahesh.tasks.repository;
  
  
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;
import org.springframework.stereotype.Repository;
  
import in.mahesh.tasks.usermodel.User;
  
@Repository
public interface UserRepository extends MongoRepository<User,String> {
    @Query("{email :?0}")
    User findByEmail(String email);
      
  
}


Step 5: Create the service package and in that package create the Java class and it named as the UserService for handling the services of the project.

Go to the src > in.mahesh.tasks > service > UserService and put the below code:

Java




package in.mahesh.tasks.service;
  
  
import in.mahesh.tasks.usermodel.User;
  
import java.util.List;
  
  
public interface UserService {
  
       
     public List<User> getAllUser()  ;
       
     public User findUserProfileByJwt(String jwt);
       
     public User findUserByEmail(String email) ;
       
     public User findUserById(String userId) ;
  
     public List<User> findAllUsers();
        
           
}


Step 6: Create the service package and in that package create the java class and it named as the UserServiceImplementation for handling the services of the project.

Go to the src > in.mahesh.tasks > service > UserServiceImplementation and put the below code:

Java




package in.mahesh.tasks.service;
  
import in.mahesh.tasks.repository.UserRepository;
  
  
import in.mahesh.tasks.usermodel.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
  
  
import java.util.ArrayList;
import java.util.List;
  
  
@Service
public class UserServiceImplementation implements UserDetailsService {
  
    @Autowired
    private UserRepository userRepository;
      
    public UserServiceImplementation(UserRepository userRepository) {
        this.userRepository=userRepository;
    }
      
      
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByEmail(username);
        System.out.println(user);
         
        if(user==null) {
            throw new UsernameNotFoundException("User not found with this email"+username);
  
        }
  
          
        System.out.println("Loaded user: " + user.getEmail() + ", Role: " + user.getRole());
        List<GrantedAuthority> authorities = new ArrayList<>();
        return new org.springframework.security.core.userdetails.User(
                user.getEmail(),
                user.getPassword(),
                authorities);
    }
}


Step 7: Create the SecurityConfig package and in that package create the java class and it named as the ApplicationConfig for handling the security of the project.

Go to the src > in.mahesh.tasks > SecurityConfig > ApplicationConfig and put the below code:

Java




package in.mahesh.tasks.SecurityConfig;
  
import jakarta.servlet.http.HttpServletRequest;
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.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
  
import java.util.Arrays;
import java.util.Collections;
  
@Configuration
public class ApplicatonConfig {
  
    @SuppressWarnings("deprecation")
    @Bean
    SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.sessionManagement(management -> management.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authorizeRequests(
                        authorize -> authorize.requestMatchers("/api/**")
                        .authenticated().anyRequest().permitAll())
                .addFilterBefore(new JwtTokenValidator(), BasicAuthenticationFilter.class)
                .csrf(csrf -> csrf.disable())
                .cors(cors -> cors.configurationSource(corsConfigurationSource()));
                //.httpBasic(Customizer.withDefaults())
                //.formLogin(Customizer.withDefaults());
        return http.build();
    }
  
    private CorsConfigurationSource corsConfigurationSource() {
        return new CorsConfigurationSource() {
            @Override
            public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
                CorsConfiguration ccfg = new CorsConfiguration();
                ccfg.setAllowedOrigins(Arrays.asList("http://localhost:3000"));
                ccfg.setAllowedMethods(Collections.singletonList("*"));
                ccfg.setAllowCredentials(true);
                ccfg.setAllowedHeaders(Collections.singletonList("*"));
                ccfg.setExposedHeaders(Arrays.asList("Authorization"));
                ccfg.setMaxAge(3600L);
                return ccfg;
  
            }
        };
  
    }
  
    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
  
}


Step 8: In same package create the java class and it named as the JwtProvider for handling the provides the token of the project.

Go to the src > in.mahesh.tasks > SecurityConfig > JwtProvider and put the below code:

Java




package in.mahesh.tasks.SecurityConfig;
  
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
  
import javax.crypto.SecretKey;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
  
public class JwtProvider {
    static SecretKey key = Keys.hmacShaKeyFor(JwtConstant.SECRET_KEY.getBytes());
  
    public static String generateToken(Authentication auth) {
        Collection<? extends GrantedAuthority> authorities = auth.getAuthorities();
        String roles = populateAuthorities(authorities);
        @SuppressWarnings("deprecation")
        String jwt = Jwts.builder()
                .setIssuedAt(new Date())
                .setExpiration(new Date(new Date().getTime()+86400000))
                .claim("email", auth.getName())
                .claim( "authorities",roles)
                .signWith(key)
                .compact();
        System.out.println("Token for parsing in JwtProvider: " + jwt);
        return jwt;
  
    }
  
    private static String populateAuthorities(Collection<? extends GrantedAuthority> authorities) {
        Set<String> auths = new HashSet<>();
        for(GrantedAuthority authority: authorities) {
            auths.add(authority.getAuthority());
        }
        return String.join(",",auths);
    }
  
  
    @SuppressWarnings("deprecation")
    public static String getEmailFromJwtToken(String jwt) {
        jwt = jwt.substring(7); // Assuming "Bearer " is removed from the token
        try {
            //Claims claims=Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(jwt).getBody();
            Claims claims = Jwts.parser().setSigningKey(key).build().parseClaimsJws(jwt).getBody();
            String email = String.valueOf(claims.get("email"));
            System.out.println("Email extracted from JWT: " + claims);
            return email;
        } catch (Exception e) {
            System.err.println("Error extracting email from JWT: " + e.getMessage());
            e.printStackTrace();
            return null;
        }
    }
  
}


Step 9: In same package create the java class and it named as the JwtTokenValidator for handling the provides the validation of the token.

Go to the src > in.mahesh.tasks > SecurityConfig > JwtTokenValidator and put the below code:

Java




package in.mahesh.tasks.SecurityConfig;
  
  
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
  
  
import javax.crypto.SecretKey;
import java.io.IOException;
import java.util.List;
  
public class JwtTokenValidator extends OncePerRequestFilter {
  
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String jwt = request.getHeader(JwtConstant.JWT_HEADER);
        System.out.println("JWT Token in JwtTokenValidator: " + jwt);
        if (jwt != null && jwt.startsWith("Bearer ")) {
            jwt = jwt.substring(7);
              
            System.out.println("JWT Token in JwtTokenValidator: " + jwt);
            try {
                SecretKey key = Keys.hmacShaKeyFor(JwtConstant.SECRET_KEY.getBytes());
                @SuppressWarnings("deprecation")
                Claims claims = Jwts.parser().setSigningKey(key).build().parseClaimsJws(jwt).getBody();
                System.out.print(claims);
  
                String email = String.valueOf(claims.get("email"));
                System.out.print(email);
                String authorities = String.valueOf(claims.get("authorities"));
                List<GrantedAuthority> auth = AuthorityUtils.commaSeparatedStringToAuthorityList(authorities);
                Authentication authentication = new UsernamePasswordAuthenticationToken(email, null, auth);
                SecurityContextHolder.getContext().setAuthentication(authentication);
  
            } catch (Exception e) {
                throw new BadCredentialsException("Invalid token", e);
            }
        }
  
        filterChain.doFilter(request, response);
    }
}


Step 10: In same package create the java class and it named as the JwtConstant for handling the provides the jwt header and secret key of the token.

Go to the src > in.mahesh.tasks > SecurityConfig > JwtConstant and put the below code:

Java




package in.mahesh.tasks.SecurityConfig;
  
public class JwtConstant {
    public static final String SECRET_KEY = "wpembytrwcvnryxksdbqwjebruyGHyudqgwveytrtrCSnwifoesarjbwe";
    public static final String JWT_HEADER = "Authorization";
}


Step 11: Create the controller package and in that package create the java class and it named as the UserController for handling the request of the project.

Go to the src > in.mahesh.tasks > controller > UserController and put the below code:

Java




package in.mahesh.tasks.controller;
  
  
import in.mahesh.tasks.repository.UserRepository;
import in.mahesh.tasks.response.AuthResponse;
import in.mahesh.tasks.service.UserServiceImplementation;
import in.mahesh.tasks.service.UserService;
import in.mahesh.tasks.SecurityConfig.JwtProvider;
import in.mahesh.tasks.usermodel.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
  
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
  
@RestController
@RequestMapping("/auth")
public class UserController {
  
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private PasswordEncoder passwordEncoder;
  
     
    @Autowired
    private UserServiceImplementation customUserDetails;
      
    @Autowired
    private UserService userService;
  
  
  
  
    @PostMapping("/signup")
    public ResponseEntity<AuthResponse> createUserHandler(@RequestBody User user)  {
        String email = user.getEmail();
        String password = user.getPassword();
        String fullName = user.getFullName();
        String mobile = user.getMobile();
        String role = user.getRole();
  
        User isEmailExist = userRepository.findByEmail(email);
        if (isEmailExist != null) {
            //throw new Exception("Email Is Already Used With Another Account");
  
        }
        User createdUser = new User();
        createdUser.setEmail(email);
        createdUser.setFullName(fullName);
        createdUser.setMobile(mobile);
        createdUser.setRole(role);
        createdUser.setPassword(passwordEncoder.encode(password));
          
        User savedUser = userRepository.save(createdUser);
          userRepository.save(savedUser);
        Authentication authentication = new UsernamePasswordAuthenticationToken(email,password);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        String token = JwtProvider.generateToken(authentication);
  
  
        AuthResponse authResponse = new AuthResponse();
        authResponse.setJwt(token);
        authResponse.setMessage("Register Success");
        authResponse.setStatus(true);
        return new ResponseEntity<AuthResponse>(authResponse, HttpStatus.OK);
  
    }
  
  
  
  
  
    @PostMapping("/signin")
    public ResponseEntity<AuthResponse> signin(@RequestBody User loginRequest) {
        String username = loginRequest.getEmail();
        String password = loginRequest.getPassword();
  
        System.out.println(username+"-------"+password);
  
        Authentication authentication = authenticate(username,password);
        SecurityContextHolder.getContext().setAuthentication(authentication);
  
        String token = JwtProvider.generateToken(authentication);
        AuthResponse authResponse = new AuthResponse();
  
        authResponse.setMessage("Login success");
        authResponse.setJwt(token);
        authResponse.setStatus(true);
  
        return new ResponseEntity<>(authResponse,HttpStatus.OK);
    }
  
  
  
      
    private Authentication authenticate(String username, String password) {
  
        System.out.println(username+"---++----"+password);
  
        UserDetails userDetails = customUserDetails.loadUserByUsername(username);
  
        System.out.println("Sig in in user details"+ userDetails);
  
        if(userDetails == null) {
            System.out.println("Sign in details - null" + userDetails);
  
            throw new BadCredentialsException("Invalid username and password");
        }
        if(!passwordEncoder.matches(password,userDetails.getPassword())) {
            System.out.println("Sign in userDetails - password mismatch"+userDetails);
  
            throw new BadCredentialsException("Invalid password");
  
        }
        return new UsernamePasswordAuthenticationToken(userDetails,null,userDetails.getAuthorities());
  
    }
  
  
  
}


Step 12: Create the response package and in that package create the java class and it named as the ApiResponse for handling the api response of the project.

Go to the src > in.mahesh.tasks > response > ApiResponse and put the below code:

Java




package in.mahesh.tasks.response;
  
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
  
@Data
public class ApiResponse {
    private String message;
    private boolean status;
    public ApiResponse(String string, boolean b) {
        // TODO Auto-generated constructor stub
    }
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }
    public boolean isStatus() {
        return status;
    }
    public void setStatus(boolean status) {
        this.status = status;
    }
  
}


Step 13: Create the response package and in that package create the Java class and it named as the AuthResponse for handling the auth response of the project.

Go to the src > in.mahesh.tasks > response > AuthResponse and put the below code:

Java




package in.mahesh.tasks.response;
  
  
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
  
@AllArgsConstructor
@NoArgsConstructor
public class AuthResponse {
    private String jwt;
    private String message;
    private Boolean status;
  
    public String getJwt() {
        return jwt;
    }
  
    public void setJwt(String jwt) {
        this.jwt = jwt;
    }
  
    public String getMessage() {
        return message;
    }
  
    public void setMessage(String message) {
        this.message = message;
    }
  
    public Boolean getStatus() {
        return status;
    }
  
    public void setStatus(Boolean status) {
        this.status = status;
    }
}


Step 14: Open the main class and put the below code:

Java




package in.mahesh.tasks;
  
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
  
  
  
@SpringBootApplication
public class UserServiceApplication {
  
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
  
}


Step 15: Once completed the project and run the application as spring project and once runs the application successful then it will run on the port 8081. Refer the below image for the better understanding.

Endpoints of this project

Method

Endpoints

POST

http://localhost:8081/auth/signup

POST

http://localhost:8081/auth/signin

Once completed both frontend with React and backend with Spring Security then run both applications of the project.

Final Output

Below we can refer the video to see the output of the application.

We can follow the above steps you can successful develop the react login application with the backend of the spring security of the project.



Spring Security Login Page with React

Spring Security is the most powerful and highly customizable authentication, and it is access control framework for Java enterprise applications and React is a popular JavaScript library for building for the user interfaces. Integrating Spring Security with the React frontend allows you to create the secure login pages and protect your application’s resources.

Similar Reads

Spring Security Login Page with React

The main concept involves to creating the React frontend that can be communicated with a Spring Boot backend secured with Spring Security. The react frontend will have a login page where users can input their credentials, and upon submission, these credentials will be sent to the backend for authentication. If the credentials are valid, the backend will generate a token (JWT) and send it back to the frontend. This token will be stored on the frontend side for subsequent requests to protected resources....

React – Frontend

Create the React project using the below command:...

Spring Security – Backend

...

Contact Us