0

I am currently working on an application in JAVA SPRING and ANGULAR. I am a novice and I am trying to progress in these two languages.

I am currently finishing the entire security part but there is one last point that is blocking me. When I log in to my application, authentication fails even though the credentials are correct. I retrieve the information correctly but when sending it to the back-end it blocks.

The problem comes from a constant which apparently is not in the right format but I can't figure out how to change that. I first tried putting it in JSON format but that obviously wasn't the right thing to do.

I share the code with you below:

In the SPRING backend:

Here is my security configuration


import java.util.Arrays;
import java.util.Collections;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.header.writers.StaticHeadersWriter;

import com.tracker.EsportTracker.service.impl.AppUserDetailsService;
import com.tracker.EsportTracker.service.impl.UserService;

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    
    @Autowired
    UserService userService;
    
    @Autowired
    AuthenticationSuccessHandler authenticationSuccessHandler;
    
    @Autowired
    private AppUserDetailsService appUserDetailsService;

    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(appUserDetailsService).passwordEncoder(bCryptPasswordEncoder);
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
        http.csrf(AbstractHttpConfigurer::disable);
        http.authorizeHttpRequests(
                auth-> auth
                .requestMatchers("/user/**", "/users/**","/tournaments/**","/tours/**").permitAll()
                .requestMatchers("").hasRole("ADMIN")
                .requestMatchers("").hasRole("USER")
                .requestMatchers("/login/user").authenticated()
                .anyRequest().authenticated()
          )
           .userDetailsService(appUserDetailsService)
           .formLogin(
                   formLogin -> formLogin
                   .loginPage("/login/user")
                   .loginProcessingUrl("/auth")
                   .defaultSuccessUrl("/")
                   .successHandler(authenticationSuccessHandler)
                   .permitAll()
                   )
           .logout(
                   logout -> logout
                   .logoutUrl("/signout").permitAll()
                   )
           .exceptionHandling(
                   exceptionHandling -> exceptionHandling
                   .accessDeniedPage("/accesRefuse")
                   );
        return http.build();
    }
    
    @Bean
    public FilterRegistrationBean simpleCorsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.setAllowedOrigins(Arrays.asList("http://localhost:4200","http://localhost:4200/"));
        config.setAllowedMethods(Collections.singletonList("*"));
        config.setAllowedHeaders(Collections.singletonList("*"));
        source.registerCorsConfiguration("/**", config);
        FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
        bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
        return bean;
    }
}

Then the AuthenticationSuccessHandlerImp class which is implemented in the latter


import java.io.IOException;
import java.util.Collection;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import com.tracker.EsportTracker.entities.User;
import com.tracker.EsportTracker.service.impl.UserService;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

@Component
public class AuthenticationSuccessHandlerImp implements AuthenticationSuccessHandler{
    
    @Autowired
    UserService userService;
    
    @Autowired
    HttpSession session;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        response.setStatus(HttpServletResponse.SC_OK);
        boolean admin = false;
        String username = authentication.getName();
        User personne=userService.findByUsername(username);
        session.setAttribute("User",personne);
    }

} 

Finally the controller which manages the connection


import java.security.Principal;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.tracker.EsportTracker.entities.User;
import com.tracker.EsportTracker.service.interfaces.IUserService;

@RestController
@RequestMapping(value = "/login")
public class LoginController {
    
    @Autowired
    IUserService userService;

    @CrossOrigin
    @RequestMapping(value="/user")
    public ResponseEntity<User> login(Principal principal) {
        System.out.println(principal);
        if (principal != null) {
            User user = userService.findByUsername(principal.getName());
            return ResponseEntity.ok(user);
        } else {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
        }
    }
} 

In the ANGULAR FRONT:

Here is my typed text for the login component

import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { AppService } from '../services/app.service';
import { UserService } from '../services/user.service';
import { User } from '../models/user';
import { SharedService } from '../services/shared.service';
import { UserComponent } from '../user/user.component';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent {
  user = '';
  credentials = {username:'', password:''}
  constructor(private appService:AppService,private httplClient:HttpClient,private router:Router,private userService:UserService, private sharedService: SharedService) { }
  login() {
    console.log("username=" + this.credentials.username + " password=" + this.credentials.password);
  
    this.appService.authenticate(this.credentials, () => {
    });
  
    this.userService.findOneByUsername(this.credentials.username).subscribe(
      (data: User) => {
        var user: User = data;
        localStorage.setItem("UserId", user.idUser.toString());
        localStorage.setItem("Username", user.username.toString());

        this.userService.getUserTournaments(user.idUser);
        
  
        this.sharedService.changeUsername(user.username);

        this.router.navigateByUrl("/users");
      },
      (error) => {
        console.error("Une erreur s'est produite lors de la récupération des données de l'utilisateur :", error);
      }
    );
  
    return false;
  }
  

}

Then the service that connects to the back

import { Injectable } from '@angular/core';
import { environment } from 'src/environments/environment.ts';

@Injectable({
  providedIn: 'root'
})
export class AppService {
  authenticated = false;
  responseAll: any;
  isAdmin = false;
  str: any;

  constructor(private httpClient: HttpClient) { }

  authenticate(credentials: any, callback: any) {
    const headers = new HttpHeaders({
      Authorization: 'Basic ' + btoa(credentials.username + ':' + credentials.password)
    });
    const authEndpoint = environment.apiBaseUrl + 'login/user';
    this.httpClient.get(authEndpoint, { headers:headers }).subscribe(
      (response) => {
        this.authenticated = true;
        this.responseAll = response;
        this.isAdmin = this.checkIfAdmin(response);
        this.str = 'Set your value here based on the response';


        if (callback) {
          callback();
        }
      },
      (error) => {
        console.error('Authentication error:', error);
        this.authenticated = false;
        this.isAdmin = false;
        this.responseAll = null;
        this.str = null;
      }
    );
  }

  private checkIfAdmin(response: any): boolean {
    return false;
  }
}

 

The error that appears is:

Honestly, I looked in the Angular documentation but I don't know what to do anymore.

HttpErrorResponse
error
: 
null
headers
: 
HttpHeaders
lazyInit
: 
() => {…}
length
: 
0
name
: 
""
arguments
: 
(...)
caller
: 
(...)
[[FunctionLocation]]
: 
http.mjs:64
[[Prototype]]
: 
ƒ ()
[[Scopes]]
: 
Scopes[4]
lazyUpdate
: 
null
normalizedNames
: 
Map(0) {size: 0}
[[Prototype]]
: 
Object
message
: 
"Http failure response for http://localhost:7070/login/user: 401 OK"
name
: 
"HttpErrorResponse"
ok
: 
false
status
: 
401
statusText
: 
"OK"
url
: 
"http://localhost:7070/login/user"
[[Prototype]]
: 
HttpResponseBase 

2023-12-06T11:58:17.036+01:00[0;39m [32mDEBUG[0;39m [35m19728[0;39m [2m---[0;39m [2m[nio-7070-exec-3][0;39m [36mo.s.security.web.FilterChainProxy       [0;39m [2m:[0;39m Securing GET /login/user
[2m2023-12-06T11:58:17.036+01:00[0;39m [32mDEBUG[0;39m [35m19728[0;39m [2m---[0;39m [2m[nio-7070-exec-2][0;39m [36mo.s.security.web.FilterChainProxy       [0;39m [2m:[0;39m Securing GET /users/secu/GotaKev
[2m2023-12-06T11:58:17.042+01:00[0;39m [32mDEBUG[0;39m [35m19728[0;39m [2m---[0;39m [2m[nio-7070-exec-3][0;39m [36mo.s.security.web.FilterChainProxy       [0;39m [2m:[0;39m Secured GET /login/user
[2m2023-12-06T11:58:17.050+01:00[0;39m [32mDEBUG[0;39m [35m19728[0;39m [2m---[0;39m [2m[nio-7070-exec-2][0;39m [36mo.s.security.web.FilterChainProxy       [0;39m [2m:[0;39m Secured GET /users/secu/GotaKev
[2m2023-12-06T11:58:17.058+01:00[0;39m [32mDEBUG[0;39m [35m19728[0;39m [2m---[0;39m [2m[nio-7070-exec-3][0;39m [36mo.s.s.w.a.AnonymousAuthenticationFilter [0;39m [2m:[0;39m Set SecurityContextHolder to anonymous SecurityContext
null
je suis la méthode findByUsername de la classe serviceGotaKev
[2m2023-12-06T11:58:17.163+01:00[0;39m [32mDEBUG[0;39m [35m19728[0;39m [2m---[0;39m [2m[nio-7070-exec-2][0;39m [36mo.s.s.w.a.AnonymousAuthenticationFilter [0;39m [2m:[0;39m Set SecurityContextHolder to anonymous SecurityContext
[2m2023-12-06T11:58:17.173+01:00[0;39m [32mDEBUG[0;39m [35m19728[0;39m [2m---[0;39m [2m[nio-7070-exec-5][0;39m [36mo.s.security.web.FilterChainProxy       [0;39m [2m:[0;39m Securing GET /users
[2m2023-12-06T11:58:17.173+01:00[0;39m [32mDEBUG[0;39m [35m19728[0;39m [2m---[0;39m [2m[nio-7070-exec-4][0;39m [36mo.s.security.web.FilterChainProxy       [0;39m [2m:[0;39m Securing GET /tournaments
[2m2023-12-06T11:58:17.173+01:00[0;39m [32mDEBUG[0;39m [35m19728[0;39m [2m---[0;39m [2m[nio-7070-exec-5][0;39m [36mo.s.security.web.FilterChainProxy       [0;39m [2m:[0;39m Secured GET /users
[2m2023-12-06T11:58:17.175+01:00[0;39m [32mDEBUG[0;39m [35m19728[0;39m [2m---[0;39m [2m[nio-7070-exec-4][0;39m [36mo.s.security.web.FilterChainProxy       [0;39m [2m:[0;39m Secured GET /tournaments
[2m2023-12-06T11:58:17.175+01:00[0;39m [32mDEBUG[0;39m [35m19728[0;39m [2m---[0;39m [2m[nio-7070-exec-6][0;39m [36mo.s.security.web.FilterChainProxy       [0;39m [2m:[0;39m Securing GET /users/secu/GotaKev
[2m2023-12-06T11:58:17.175+01:00[0;39m [32mDEBUG[0;39m [35m19728[0;39m [2m---[0;39m [2m[nio-7070-exec-6][0;39m [36mo.s.security.web.FilterChainProxy       [0;39m [2m:[0;39m Secured GET /users/secu/GotaKev
je suis la méthode findByUsername de la classe serviceGotaKev
[2m2023-12-06T11:58:17.185+01:00[0;39m [32mDEBUG[0;39m [35m19728[0;39m [2m---[0;39m [2m[nio-7070-exec-6][0;39m [36mo.s.s.w.a.AnonymousAuthenticationFilter [0;39m [2m:[0;39m Set SecurityContextHolder to anonymous SecurityContext
[2m2023-12-06T11:58:17.187+01:00[0;39m [32mDEBUG[0;39m [35m19728[0;39m [2m---[0;39m [2m[nio-7070-exec-7][0;39m [36mo.s.security.web.FilterChainProxy       [0;39m [2m:[0;39m Securing GET /users/1/tournaments
[2m2023-12-06T11:58:17.188+01:00[0;39m [32mDEBUG[0;39m [35m19728[0;39m [2m---[0;39m [2m[nio-7070-exec-7][0;39m [36mo.s.security.web.FilterChainProxy       [0;39m [2m:[0;39m Secured GET /users/1/tournaments
[2m2023-12-06T11:58:17.199+01:00[0;39m [32mDEBUG[0;39m [35m19728[0;39m [2m---[0;39m [2m[nio-7070-exec-7][0;39m [36mo.s.s.w.a.AnonymousAuthenticationFilter [0;39m [2m:[0;39m Set SecurityContextHolder to anonymous SecurityContext
[2m2023-12-06T11:58:17.203+01:00[0;39m [32mDEBUG[0;39m [35m19728[0;39m [2m---[0;39m [2m[nio-7070-exec-5][0;39m [36mo.s.s.w.a.AnonymousAuthenticationFilter [0;39m [2m:[0;39m Set SecurityContextHolder to anonymous SecurityContext
[2m2023-12-06T11:58:17.209+01:00[0;39m [32mDEBUG[0;39m [35m19728[0;39m [2m---[0;39m [2m[nio-7070-exec-4][0;39m [36mo.s.s.w.a.AnonymousAuthenticationFilter [0;39m [2m:[0;39m Set SecurityContextHolder to anonymous SecurityContext


Thanking you in advance for the help

6
  • 1
    enable your spring security DEBUG logs and edit your question to include them. Some pointers, FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source)); can be removed, read the CORS chapter in the spring security official docs on the webpage, shows you exactly how to configure CORS, you also dont need ` @CrossOrigin` annotation . You use either a bean or the annotation, not both. We cant run your code, so its impossible for us without logs they will tell you the exact reason for the 401 Commented Dec 5, 2023 at 23:29
  • 1
    also you are posting BASIC authentication to FormLogin, they are 2 completely separate ways of authenticating. You need to send username and password as FORM parameters in the body, and not as an Authorization header. stackoverflow.com/a/46333889/1840146 Commented Dec 5, 2023 at 23:32
  • @Toerktumlare So on the Angular side I have to send the information to the back via a form? like a classic form? Commented Dec 6, 2023 at 11:03
  • @Toerktumlare I don't understand how to delete this line? FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source)); Commented Dec 6, 2023 at 11:09
  • 1
    Did you read the CORS chapter in the spring security docs on their webpage before asking me? And the code i linked, is that a form? Please…. Google FormData use the code i linked. Im not going to answer more stack overflow is not a forum. Commented Dec 6, 2023 at 14:33

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.