英文:
GET http://localhost:8081/login net::ERR_TOO_MANY_REDIRECTS 302 Angular and Java
问题
我使用Spring Security v6.1.0在Java中实现了身份验证,以下是相关代码部分:
在Java端,我实现了身份验证,使用了Spring Security v6.1.0,以下是相关代码部分:
@GetMapping(value="/loginUser")
public User login(Principal principal) {
    return this.userService.findByEmail(principal.getName());
}
WebSecurityConfig 类:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .cors().and().csrf().disable()
                .authorizeHttpRequests((authorize) -> authorize
                        .requestMatchers("/", "/login").permitAll()
                        .requestMatchers("/scan",
                                "/loginUser",
                                "/users",
                                "/invoices",
                                "/dueNextWeek",
                                "/groupedByVendor",
                                "/groupedByVendorTotalAmountPerMonth",
                                "/totalAmountPerMonth").authenticated()
                )
                .formLogin((form) -> form
                        .loginPage("/login")
                        .loginProcessingUrl("/login")
                        .defaultSuccessUrl("/loginUser")
                        .permitAll()
                )
                .cors((cors) -> cors
                        .configurationSource(corsConfigurationSource())
                );
        return http.build();
    }
    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("http://localhost:4200"));
        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE"));
        configuration.setAllowedHeaders(Arrays.asList("*"));
        configuration.setAllowCredentials(true);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
UserServiceImpl 类:
@Override
public User findByEmail(String email) {
    Optional<User> user = this.userRepository.findByEmail(email);
    return user.get();
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    Optional<User> userOpt = userRepository.findByEmail(username);
    User user = userOpt.orElseThrow(() -> new UsernameNotFoundException(username + " not found!"));
    return org.springframework.security.core.userdetails.User.builder()
            .username(user.getEmail())
            .password(user.getPassword()).build();
}
Angular服务端:
import { Component } from '@angular/core';
import { Router } from "@angular/router";
import { AuthService } from "../authentication/auth.service";
@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent {
  form: any = {
    username: null,
    password: null
  };
  isLoggedIn = false;
  errorMessage = '';
  wrongCredentials: boolean = false;
  invalidLogin: boolean = false;
  constructor(private router: Router, private loginService: AuthService) {
  }
  onSubmit(): void {
    sessionStorage.setItem('username', this.form.username);
    sessionStorage.setItem('password', this.form.password);
    this.loginService.authenticate(this.form.username, this.form.password).subscribe(
      () => {
        this.router.navigate(['/home']);
        this.invalidLogin = false;
      },
      (err) => {
        this.invalidLogin = true;
        this.wrongCredentials = true;
      }
    )
  }
}
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from "@angular/common/http";
import { catchError, map, throwError } from "rxjs";
const AUTH_API = 'http://localhost:8081/login';
@Injectable({
  providedIn: 'root'
})
export class AuthService {
  isLoggedIn: boolean | undefined;
  constructor(private http: HttpClient) {
  }
  ngOnInit(): void {
  }
  authenticate(username: string, password: string) {
    const httpOptions: Object = {
      headers: new HttpHeaders({
        'Content-Type': 'application/json',
        'Authorization': "Basic " + btoa(username + ":" + password)
      }),
      responseType: 'text'
    };
    let credentials = { username: username, password: password };
    return this.http.post(AUTH_API, credentials, httpOptions).pipe(
      map(() => {
        let authString = 'Basic ' + btoa(username + ':' + password);
        sessionStorage.setItem('username', username);
        sessionStorage.setItem('basicAuth', authString);
        this.isLoggedIn = true;
      }),
      catchError((error) => {
        console.error('Authentication error:', error);
        return throwError(error);
      }))
  }
  isUserLoggedIn() {
    let basicAuth = sessionStorage.getItem('basicAuth');
    return basicAuth != null;
  }
  logOut() {
    sessionStorage.removeItem('username');
    sessionStorage.removeItem('basicAuth');
    this.isLoggedIn = false;
  }
}
当我使用Postman从 /login 发送POST请求到Java应用程序时,我会得到认证的User作为响应,我认为这是正常工作的方式,但是当我从Angular应用程序发送请求时,我得到了 GET http://localhost:8081/login net::ERR_TOO_MANY_REDIRECTS 302。我做错了什么?
英文:
I implemented authentication in Java using Spring Security v6.1.0 and this is the endpoint:
 @GetMapping(value="/loginUser")
public User login(Principal principal) {
return this.userService.findByEmail(principal.getName());
}
WebSecurityConfig class:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.cors().and().csrf().disable()
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers("/", "/login").permitAll()
.requestMatchers("/scan",
"/loginUser",
"/users",
"/invoices",
"/dueNextWeek",
"/groupedByVendor",
"/groupedByVendorTotalAmountPerMonth",
"/totalAmountPerMonth").authenticated()
)
.formLogin((form) -> form
.loginPage("/login")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/loginUser")
.permitAll()
)
.cors((cors) -> cors
.configurationSource(corsConfigurationSource())
);
return http.build();
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:4200"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE"));
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
UserServiceImpl:
 @Override
public User findByEmail(String email) {
Optional<User> user = this.userRepository.findByEmail(email);
return user.get();
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Optional<User> userOpt = userRepository.findByEmail(username);
User user = userOpt.orElseThrow(() -> new UsernameNotFoundException(username + " not found!"));
return org.springframework.security.core.userdetails.User.builder()
.username(user.getEmail())
.password(user.getPassword()).build();
}
The angular service:
import {Component} from '@angular/core';
import {Router} from "@angular/router";
import {AuthService} from "../authentication/auth.service";
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent {
form: any = {
username: null,
password: null
};
isLoggedIn = false;
errorMessage = '';
wrongCredentials: boolean = false;
invalidLogin: boolean = false;
constructor(private router: Router, private loginService: AuthService) {
}
onSubmit(): void {
sessionStorage.setItem('username', this.form.username);
sessionStorage.setItem('password', this.form.password);
this.loginService.authenticate(this.form.username, this.form.password).subscribe(
() => {
this.router.navigate(['/home']);
this.invalidLogin = false;
},
(err) => {
this.invalidLogin = true;
this.wrongCredentials = true;
}
)
}
}
import {Injectable} from '@angular/core';
import {HttpClient, HttpHeaders} from "@angular/common/http";
import {catchError, map, throwError} from "rxjs";
const AUTH_API = 'http://localhost:8081/login';
@Injectable({
providedIn: 'root'
})
export class AuthService {
isLoggedIn: boolean | undefined;
constructor(private http: HttpClient) {
}
ngOnInit(): void {
}
authenticate(username: string, password: string) {
const httpOptions: Object = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': "Basic " + btoa(username + ":" + password)
}),
responseType: 'text'
};
let credentials = {username: username, password: password};
return this.http.post(AUTH_API, credentials, httpOptions).pipe(
map(() => {
let authString = 'Basic ' + btoa(username + ':' + password);
sessionStorage.setItem('username', username);
sessionStorage.setItem('basicAuth', authString);
this.isLoggedIn = true;
}),
catchError((error) => {
console.error('Authentication error:', error);
return throwError(error);
}))
}
isUserLoggedIn() {
let basicAuth = sessionStorage.getItem('basicAuth');
return basicAuth != null;
}
logOut() {
sessionStorage.removeItem('username');
sessionStorage.removeItem('basicAuth');
this.isLoggedIn = false;
}
}
When I send POST request from postman to the java application on /login, I get the authenticated User as a response, which I guess it works how it should work, but when I send a request from the angular application, I get GET http://localhost:8081/login net::ERR_TOO_MANY_REDIRECTS 302. Where do I go wrong?
答案1
得分: 2
我已经找到了问题。这段代码
.formLogin((form) -> form
.loginPage("/login")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/loginUser")
.permitAll()
)
导致了HTTP 302循环。我已经更改了filterChain方法:
    @Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.cors().and().csrf()
.disable()
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers(HttpMethod.OPTIONS, "/**")
.permitAll()
.requestMatchers("/login")
.permitAll()
.requestMatchers(
//所有其他列出的URL
).authenticated());
return http.build();
现在的端点是:
@RequestMapping(value="/login")
public ResponseEntity<User> login(@RequestBody LoginUserDTO loginUserDTO) {
return ResponseEntity.ok(this.userService.findByEmail(loginUserDTO.username()));
}
现在向localhost:8081/login发送POST请求可以正常工作。
英文:
I have found the problem. This piece of code
.formLogin((form) -> form
.loginPage("/login")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/loginUser")
.permitAll()
)
was causing the HTTP 302 loop. I have changed the filterChain method:
    @Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.cors().and().csrf()
.disable()
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers(HttpMethod.OPTIONS, "/**")
.permitAll()
.requestMatchers("/login")
.permitAll()
.requestMatchers(
//all other urls listed
).authenticated());
return http.build();
And the endpoint now is:
@RequestMapping(value="/login")
public ResponseEntity<User> login(@RequestBody LoginUserDTO loginUserDTO) {
return ResponseEntity.ok(this.userService.findByEmail(loginUserDTO.username()));
}
Making POST requests to localhost:8081/login works perfectly fine now.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论