Angular与Spring Boot CORS跨域错误解决方案咨询
问题描述
Access to XMLHttpRequest at 'http://localhost:8080/basicauth' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
相关配置如下:
AuthenticationBean.java
package com.sofi.rest.webservices.restfulwebservices.basic.auth; public class AuthenticationBean { private String message; public AuthenticationBean(String message) { this.message = message; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } @Override public String toString() { return String.format("HelloWorldBean [message=%s]", message); } }
BasicAuthenticationController.java
package com.sofi.rest.webservices.restfulwebservices.basic.auth; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; //Controller @CrossOrigin(origins="http://localhost:4200") @RestController public class BasicAuthenticationController { @GetMapping(path = "/basicauth") public AuthenticationBean helloWorldBean() { //throw new RuntimeException("Some Error has Happened! Contact Support at ***-***"); return new AuthenticationBean("You are authenticated"); } }
SpringSecurityConfigurationBasicAuth.java
package com.sofi.rest.webservices.restfulwebservices.basic.auth; import static org.springframework.security.config.Customizer.withDefaults; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.web.SecurityFilterChain; @Configuration @EnableWebSecurity @EnableMethodSecurity public class SpringSecurityConfigurationBasicAuth { @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests(auth -> auth.requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()); http.csrf(csrf -> csrf.disable()); http.httpBasic(withDefaults()); return http.build(); } }
WebConfig.java
package com.sofi.rest.webservices.restfulwebservices.basic.auth.config; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("http://localhost:4200") .allowedMethods(HttpMethod.GET.name(), HttpMethod.POST.name(), HttpMethod.PUT.name(), HttpMethod.DELETE.name()) .allowedHeaders(HttpHeaders.CONTENT_TYPE, HttpHeaders.AUTHORIZATION); } }
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.5</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.sofi.rest.webservices</groupId> <artifactId>restful-web-services</artifactId> <version>0.0.1-SNAPSHOT</version> <name>restful-web-services</name> <description>Demo project for Spring Boot</description> <properties> <java.version>17</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
http-intercepter-basic-auth.service.ts
import { HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { BasicAuthenticationService } from '../basic-authentication.service'; @Injectable({ providedIn: 'root' }) export class HttpIntercepterBasicAuthService implements HttpInterceptor { constructor( private basicAuthenticationService: BasicAuthenticationService ) { } intercept(request: HttpRequest<any>, next: HttpHandler) { let basicAuthHeaderString = this.basicAuthenticationService.getAuthenticatedToken(); let username = this.basicAuthenticationService.getAuthenticatedUser(); if (basicAuthHeaderString && username) { request = request.clone({ setHeaders: { Authorization: basicAuthHeaderString } }) } return next.handle(request); } }
解决方案
你的配置已包含部分CORS设置,但问题核心是Spring Security未关联CORS配置——仅放开OPTIONS请求权限不足以让预检响应带上Access-Control-Allow-Origin头,需按以下步骤调整:
1. 给Spring Security添加CORS支持
修改SpringSecurityConfigurationBasicAuth.java,在securityFilterChain方法中加入http.cors(withDefaults());,让Spring Security应用全局CORS规则:
@Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests(auth -> auth.requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()); // 启用CORS,使用全局配置 http.cors(withDefaults()); http.csrf(csrf -> csrf.disable()); http.httpBasic(withDefaults()); return http.build(); }
2. 清理重复代码
BasicAuthenticationController.java中重复定义了@CrossOrigin和导入语句,删除重复部分:
package com.sofi.rest.webservices.restfulwebservices.basic.auth; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; //Controller @CrossOrigin(origins="http://localhost:4200") @RestController public class BasicAuthenticationController { @GetMapping(path = "/basicauth") public AuthenticationBean helloWorldBean() { //throw new RuntimeException("Some Error has Happened! Contact Support at ***-***"); return new AuthenticationBean("You are authenticated"); } }
3. 完善WebConfig的CORS配置
补充allowCredentials(true)以支持携带认证信息,同时显式允许OPTIONS方法:
@Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("http://localhost:4200") .allowedMethods(HttpMethod.GET.name(), HttpMethod.POST.name(), HttpMethod.PUT.name(), HttpMethod.DELETE.name(), HttpMethod.OPTIONS.name()) .allowedHeaders(HttpHeaders.CONTENT_TYPE, HttpHeaders.AUTHORIZATION) .allowCredentials(true); }
4. 重启服务测试
修改完成后,重启Spring Boot和Angular应用,再次请求/basicauth接口即可解决CORS问题。
内容的提问来源于stack exchange,提问作者SN55

