Angular调用Spring Security接口出现ERR_TOO_MANY_REDIRECTS 302错误
你使用Spring Security v6.1.0实现认证功能,Postman向/login发送POST请求能正常获取响应,但Angular发起请求时出现GET http://localhost:8081/login net::ERR_TOO_MANY_REDIRECTS 302错误,问题根源在于前后端认证方式不匹配,导致重定向循环,具体原因及解决方案如下:
核心问题点
1. 表单登录与Basic Auth的冲突
你的Spring Security配置采用的是**表单登录(formLogin)**流程,但Angular端却在请求头中添加了Authorization: Basic ...字段,触发了Spring Security的Basic认证过滤器。两种认证流程互相干扰:
- 表单登录依赖Session Cookie维护认证状态,而Basic Auth是基于请求头的单次认证
- Spring Security先尝试Basic认证,认证成功后触发重定向到
/loginUser,但如果会话未正确建立,/loginUser的请求会被判定为未认证,再次重定向到/login,形成循环
2. 请求格式不匹配
Spring Security的表单登录默认接收application/x-www-form-urlencoded格式的POST请求,参数为username和password,但Angular端发送的是JSON格式请求,同时额外携带Basic Auth头,不符合表单登录的预期格式,导致认证失败,触发重定向到登录页,反复重定向超出浏览器限制。
解决方案
方案一:改用Basic Authentication(适配Angular当前实现)
修改Spring Security配置,启用Basic认证,移除表单登录相关配置:
@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() .anyRequest().authenticated() ) .httpBasic(Customizer.withDefaults()) // 启用Basic认证 .cors((cors) -> cors .configurationSource(corsConfigurationSource()) ); return http.build(); } // 保留Cors、passwordEncoder等其他Bean配置 }
同时调整Angular的AuthService,直接请求认证后的接口验证状态,无需发送JSON体:
authenticate(username: string, password: string) { const httpOptions = { headers: new HttpHeaders({ 'Authorization': "Basic " + btoa(username + ":" + password) }) }; // 直接请求需要认证的/loginUser接口验证身份 return this.http.get('http://localhost:8081/loginUser', httpOptions).pipe( map((user) => { let authString = 'Basic ' + btoa(username + ':' + password); sessionStorage.setItem('username', username); sessionStorage.setItem('basicAuth', authString); this.isLoggedIn = true; return user; }), catchError((error) => { console.error('Authentication error:', error); return throwError(error); }) ); }
方案二:保持表单登录,修正Angular请求格式
让Angular发送符合表单登录要求的请求格式,移除Basic Auth头,同时开启Cookie携带:
authenticate(username: string, password: string) { // 构建x-www-form-urlencoded格式的参数 const params = new URLSearchParams(); params.set('username', username); params.set('password', password); const httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/x-www-form-urlencoded' }), withCredentials: true // 携带Session Cookie }; return this.http.post(AUTH_API, params.toString(), httpOptions).pipe( map(() => { // 表单登录成功后,Session由Cookie维护,无需存储Basic Auth信息 sessionStorage.setItem('username', username); this.isLoggedIn = true; }), catchError((error) => { console.error('Authentication error:', error); return throwError(error); }) ); }
同时删除Angular组件中不安全的密码存储代码:
// 移除这行代码 sessionStorage.setItem('password', this.form.password);
额外建议
如果是前后端分离架构,更推荐使用JWT认证方式,避免Session和Cookie带来的跨域问题,同时简化状态维护逻辑。
内容的提问来源于stack exchange,提问作者Programmer2B

