无法使用 Spring Boot 和 Angular 修复 CORS 问题 [重复]

Posted

技术标签:

【中文标题】无法使用 Spring Boot 和 Angular 修复 CORS 问题 [重复]【英文标题】:Unable to fix CORS issue with Spring Boot and Angular [duplicate] 【发布时间】:2020-07-19 06:15:29 【问题描述】:

我是 Spring Boot 和 Angular 的新手,正在努力解决 CORS 问题。

我想实现一个全局 CORS 过滤器并尝试实现 CorsFilter、WebMvcConfigurer 并尝试使用 WebMvcConfigurerAdapter 类,但这些方法似乎都不起作用。我知道我错过了一些东西,但不知道是什么。如果有人可以在我的代码中找到解决方案,那将是很大的帮助。

如果有帮助的话,我还实现了基本身份验证并添加了该代码。

这是我的代码。

Angular API 调用

api.service.ts

import  Injectable  from '@angular/core';
import  HttpClient, HttpHeaders  from '@angular/common/http';

@Injectable(
  providedIn: 'root'
)
export class ApiService 

  constructor(private httpClient: HttpClient)  

  userLogin(username: String, password: String) 
    let postBody = 
      "username" : username,
      "password" : password
    ;
    let httpOptions = 
      headers : new HttpHeaders(
        "Content-Type" : "application/json",
        "Authorization" : "Basic " + btoa('myUsername:myPassword')
      )
    
    return this.httpClient.post("http://localhost:8080/userLogin", postBody, httpOptions);
  


这是我的 API 代码。

MainApp.java

@SpringBootApplication
public class MainApp extends SpringBootServletInitializer 
    public static void main(String... str) 
        SpringApplication.run(MainApp.class, str);
    

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) 
        return builder.sources(MainApp.class);
    


Config.java

@Configuration
public class Config 

    @Bean
    public CorsFilter corsFilter() 
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowCredentials(true);
        configuration.setAllowedOrigins(Collections.singletonList("*"));
        configuration.setAllowedHeaders(Arrays.asList("Origin", "Content-Type", "Accept"));
        configuration.setAllowedMethods(Arrays.asList("POST"));
        source.registerCorsConfiguration("/**", configuration);
        return new CorsFilter(source);
    

NotebookController.java

@RestController
public class NotebookController 

    @Autowired
    IUsersRepo usersRepo;
    @Autowired
    INotesRepo notesRepo;

    @PostMapping("userLogin")
    @ResponseBody
    public ResponseEntity<String> userLogin(@RequestParam("username") String username, @RequestParam("password") String password) 
        ObjectWriter objectWriter = new ObjectMapper().writer().withDefaultPrettyPrinter();
        List<Users> usersList = usersRepo.findByUsernameEqualsAndPasswordEquals(username, password);
        boolean userVerified = usersList.size() > 0 ? true : false;
        HashMap<String, Boolean> outputMap = new HashMap<>();
        outputMap.put("authenticated", userVerified);
        String outputJson = "";
        try 
            outputJson = objectWriter.writeValueAsString(outputMap);
         catch (JsonProcessingException e) 
            e.printStackTrace();
        
        outputJson = outputJson.toString();
        ResponseEntity<String> response = new ResponseEntity<String>(outputJson, HttpStatus.OK);
        return response;
    

Authentication.java

@Configuration
@EnableWebSecurity
public class Authentication extends WebSecurityConfigurerAdapter 

    @Autowired
    AuthenticationEntryPoint authEntryPoint;

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        super.configure(http);
        http.cors().and().csrf().disable();

        //Authorise all incoming requests
        http.authorizeRequests().and().httpBasic();
        http.authorizeRequests().anyRequest().authenticated();

        //Use AuthenticationEntryPoint to authorise username/password
        http.httpBasic().authenticationEntryPoint(authEntryPoint);
    

    @Bean
    public CorsFilter corsFilter() 
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowCredentials(true);
        configuration.setAllowedOrigins(Collections.singletonList("*"));
        configuration.setAllowedHeaders(Arrays.asList("Origin", "Content-Type", "Accept"));
        configuration.setAllowedMethods(Arrays.asList("POST"));
        source.registerCorsConfiguration("/**", configuration);
        return new CorsFilter(source);
    

    @Bean
    public BCryptPasswordEncoder getEncoder() 
        return new BCryptPasswordEncoder();
    

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception 
        String username = "myUsername";
        String password = "myPassword";

        InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> mngConfig = authenticationManagerBuilder.inMemoryAuthentication();

        mngConfig.withUser(username).password(password).roles("USER");
    


AuthEntryPoint.java

@Component
public class AuthEntryPoint extends BasicAuthenticationEntryPoint 

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response,
            AuthenticationException authException) throws IOException, ServletException 
        super.commence(request, response, authException);
        response.addHeader("WWW-Authenticate", "Basic realm=" + getRealmName());
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        PrintWriter writer = response.getWriter();
        writer.println("HTTP Status 401: Unauthorised | " + authException.getMessage());
    

    @Override
    public void afterPropertiesSet() throws Exception 
        setRealmName("Online Notebook");
        super.afterPropertiesSet();
    


请同时查看浏览器控制台。

https://imgur.com/a/hHceJDw

【问题讨论】:

imgur.com/a/hHceJDw 的图像中显示的错误消息说,“预检响应中的访问控制允许标头不允许请求标头字段“授权”” .所以你需要改变你的代码来拥有configuration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type"))。请不要将错误消息的屏幕截图发布到 Stack Overflow 的问题中。始终以文本形式复制并粘贴错误消息。 @sideshowbarker 非常感谢您的帮助。有效。我也会考虑你的建议。 【参考方案1】:

由于您使用的是 spring security ,因此您可以像下面这样配置 cors 和 spring security ,以便飞行前检查请求通过 spring security。

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http.cors().and()
            //other configurations that you want
    

    @Bean
    CorsConfigurationSource corsConfigurationSource()
    
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        //or any domain that you want to restrict to 
        configuration.setAllowedHeaders(Arrays.asList("Origin", "Content-Type", "Accept","Authorization"));
   configuration.setAllowedMethods(Arrays.asList("GET","POST"));
        //Add the method support as you like 
        UrlBasedCorsConfigurationSource source = new     UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    

您可能面临的问题是 Spring Security 不会让飞行前检查请求通过并使其失败。如需更多分析,请分享您的浏览器日志或请求中的错误。

从浏览器错误中可以看出,cors 配置不允许您添加到请求的标头 "Authorization",因为您在 cors 配置中仅指定了标头 "Origin", "Content-Type", "Accept"。将 "Authorization" 标头也添加到 cors 配置中,问题应该得到解决。

【讨论】:

我按照您的建议进行了尝试,但仍然遇到同样的错误。我已按照建议更新了 Authentication.java 文件,并在问题中也对其进行了更新。我还在最后添加了浏览器输出。 我也尝试删除 csrf 安全,但效果不佳。 @ChiranjeevJain 将授权标头添加到 configuration.setAllowedHeaders(Arrays.asList("Origin", "Content-Type", "Accept")); ,它将解决您的问题

以上是关于无法使用 Spring Boot 和 Angular 修复 CORS 问题 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

使用 spring-boot:1.5.1 和 spring-cloud-stream 时无法启动 bean 'inputBindingLifecycle'

使用 Gradle 和 Spring Boot 时无法发布到本地 maven 存储库

无法使用 Spring Boot 和 Angular 修复 CORS 问题 [重复]

无法使用 Spring Boot 和 MVC 找到/渲染 JSP 文件

无法将 Spring Data MongoDB + Spring Data JPA 与 Spring Boot 一起使用

如何解决在使用 Spring Boot 和 Spring Security 启用 CSRF 后无法正常工作的登录问题?