Spring网关+WebFlux+Security登录未认证及弹窗重复问题排查
问题:Basic认证下登录弹窗重复出现,无法完成角色获取
我开发了一个登录表单,提交到后端后调用GET接口获取已认证用户角色,但始终无法完成认证。后端采用Spring Gateway、Spring WebFlux、Spring Security、Lombok技术栈,登录弹窗会出现两次。
第一次登录截图:
第二次登录截图:
前端代码
let body = { "username": username, "password": password } let headers = new HttpHeaders(); let data = username + ':' + password let encodedCredentials = Buffer.from(data).toString('base64'); // let encodedCredentials = btoa(username + ':' + password); // encode as base64 headers = headers.append('Authorization', 'Basic ' + encodedCredentials); const observer = { next: (x: any) => { console.log(x); this.redirecting() }, error: (err: any) => { console.log(err.error) }, complete: () => console.log('Observer got a complete notification'), } this.http.post(loginUrl, body, { headers: headers, responseType: 'text', withCredentials: true }).subscribe(observer); redirecting() { console.log("called"); const roleUrl = this.url + "role"; this.userService.logIn(); const observer = { next: (x: any) => { console.log(x) }, error: (err: any) => { console.log(err.error) } } this.http.get(roleUrl, { responseType: 'text', withCredentials: true }).subscribe(observer); // this.router.navigate(['home']); }
后端Security配置
@Configuration @EnableWebFluxSecurity public class SecurityConfig { @Bean public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { return http .authorizeExchange() .pathMatchers("/api/login/").permitAll() // .pathMatchers("/api/role/").permitAll() // .pathMatchers("/api/student/**").permitAll() .anyExchange().authenticated() .and() .httpBasic(Customizer.withDefaults()) .csrf().disable() // .cors() // Customizer.withDefaults() .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("Authorization", "Content-Type")); configuration.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; } @Bean public MapReactiveUserDetailsService userDetailsService() { // System.out.println("{bcrypt}" + encoder().encode("admin")); UserDetails u1 = User .withUsername("admin") .password("{noop}admin") // encoder().encode( .authorities("ADMIN") .build(); UserDetails u2 = User .withUsername("prof") .password("{noop}prof") .authorities("PROF") .build(); UserDetails u3 = User .withUsername("abc") .password("{noop}abc") .authorities("STUDENT") .build(); return new MapReactiveUserDetailsService(u1, u2, u3); } }
Application.yml配置
server: port: 8080 # logging: # level: # org: # springframework: # security: DEBUG spring: # security: # user: # name: admin # password: admin cloud: gateway: routes: - id: user_service uri: http://localhost:8081/ predicates: - Path=/** # - Path=/api/student/** # - Path=/api/teacher/** # - Path=/api/admin/**
LoginController代码
@RestController public class LoginController { @PostMapping("/api/login") public Mono<String> myEndpoint(ServerHttpResponse response, Authentication auth) { // System.out.println("Message from Login"); if(auth.isAuthenticated()) { return Mono.just(auth.getName()); } return Mono.just("not authenticated"); } @GetMapping("/api/role") public Mono<String> getRole(ServerHttpResponse response, Authentication auth) { // System.out.println("Message from Login"); // response.setStatusCode(HttpStatus.OK); Collection<? extends GrantedAuthority> authorities = auth.getAuthorities(); List<String> roles = new ArrayList<>(); for (GrantedAuthority authority : authorities) { roles.add(authority.getAuthority()); } if (roles.isEmpty()) { return Mono.just("None"); } return Mono.just(roles.get(0)); } }
已尝试的无效操作
- 移除CORS配置代码
- 注释登录接口的
permitAll配置
内容的提问来源于stack exchange,提问作者daybreak
相关产品推荐
相关产品推荐

