我用React前端和Spring Boot后端创建了一个应用程序。
从我的React前端,我想调用Atlassian Jira REST api。这行不通。我收到此CORS错误:
Quellübergreifende (Cross-Origin) Anfrage blockiert:
Die Gleiche-Quelle-Regel verbietet das Lesen der externen Ressource auf
https://jira03.abc.com/rest/api/2/issue/.
(Grund: CORS-Anschlag schlug fehl).
英语:
Cross origin request blocked:
The cross origin rule prohibits the reading of the external ressource
https://jira03.abc.com/rest/api/2/issue/.
(Reason: CORS attack failed).
反应代码Jira数据
/**
* Creates a jira ticket for the given connection and with the given user details.
* @param connection
* @param user user who is mentioned in the ticket
*/
export function createJiraTicket(connection: {
createdAt: number,
"updatedAt": number,
"id": number,
"contactDetails": {
"createdAt": number,
"updatedAt": number,
"id": number,
"company": string,
"address": string,
"city": string,
"state": string,
"country": string,
"postalCode": number,
"companyContactPersons": [{
"fullName": string,
"title": string,
"phone": number,
"role": string,
"emaiL": string
}],
"hlagContactPersons": [{
"fullName": string,
"title": string,
"phone": number,
"role": string,
"emaiL": string
}]
},
"businessCase": {
"id": number,
"businessCaseName": string,
"ansiMessageTypes": string[],
"edifactMessageTypes": string[]
},
"ediMessageStandard": string,
"connectionTechnologyDetails": {}
},
user: { id: number, fullName: string, username: string }) {
return fetchJira(
"https://jira03.abc.com/rest/api/2/issue/", {
method: 'POST',
body: JSON.stringify({
fields: {
issuetype: {
self: "https://jira03.abc.com/rest/api/2/issuetype/36",
id: "36",
description: "",
iconUrl: "https://jira03.abc.com/secure/viewavatar?size=xsm" +
"all&avatarId=16518&avatarType=issuetype",
name: "Development Task",
subtask: false,
avatarId: 16518
},
customfield_17300: null,
customfield_13100: null,
customfield_14113: null,
project: {
self: "https://jira03.abc.com/rest/api/2/project/11400",
id: "11400",
key: "ITSCM",
name: "IT Supply Chain Management"
},
customfield_11200: [{
self: "https://jira03.abc.com/rest/api/2/user?username=MUSTERMANN",
name: "MUSTERMAN",
key: "mustema",
emailAddress: "abc@gmx.com",
displayName: "Max Mustermann",
active: true,
timeZone: "Europe/Berlin"
}],
customfield_10109: null,
customfield_16200: null,
priority: {
self: "https://jira03.abc.com/rest/api/2/priority/1",
iconUrl: "https://jira03.abc.com/images/icons/priorities/blocker.svg",
name: "Severity 1",
id: "1"
},
labels: [
"NEW_CONNECTION",
"SSW1",
connection.contactDetails.company
],
assignee: {
self: "https://jira03.abc.com/rest/api/2/user?username=mustema",
name: "mustema",
key: "mustema",
emailAddress: "abc@gmx.com",
displayName: "Max Mustermann",
active: true,
timeZone: "Europe/Berlin"
},
components: [{
self: "https://jira03.abc.com/rest/api/2/component/19201",
id: "19201",
name: "ITSCM Customer",
description: "!ITSCMCUS: ITSCM Customer"
}],
description: "Dears,\r\n\r\nkindly arrange new EDI connection: \r\n\r\n" +
connection.contactDetails +
"\r\n\r\n" +
connection.businessCase +
"\r\n\r\n" +
connection.ediMessageStandard +
"\r\n\r\n" +
connection.connectionTechnologyDetails +
"\r\n\r\nRgds, " + user.fullName,
customfield_14897: [],
customfield_10600: null,
customfield_16706: null,
customfield_12900: null,
summary: "SSW - " + connection.contactDetails.company + " // new partner for EDI connection ",
customfield_13310: null,
duedate: null
}
}),
auth: {
'user': '[USERNAME DELETED FOR STACKOVERFLOW]',
'pass': '[PASSWORD DELETED FOR STACKOVERFLOW]'
}
}
);
}
回应提取请求
/**
* Function to exchange data with the jira back end
* @param {string} url REST url
* @param options fetch options
* @returns {Promise<Response>} response from server
*/
export function fetchJira(url: string, options: any) {
// performs api calls sending the required authentication headers
const headers = {
'Content-Type': 'application/json'
};
return fetch(url, {
headers,
...options
})
.then((response: any) => {
return response.ok ? response : Promise.reject({
status: response.status,
statusText: response.statusText,
body: response.body
});
});
}
我认为Spring CORS配置一定是个问题。
Spring代码CORS配置bean
/**
* Handles the cross-origin ressource sharing.
*
* @return CORS configuration to be registered as bean
*/
@Bean
CorsConfigurationSource corsConfigurationSource() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration().applyPermitDefaultValues();
config.setAllowCredentials(true);
config.addAllowedOrigin("localhost:3000");
config.addAllowedOrigin("localhost:8080");
config.addAllowedOrigin("https://jira03.abc.com/rest/api/2/issue/");
config.addAllowedOrigin("https://jira03.abc.com/");
config.addAllowedOrigin("xxx:8080");
config.addAllowedHeader("Authorization");
config.addAllowedHeader("Content-Type");
config.addAllowedHeader("X-Requested-With");
config.addAllowedHeader("Accept");
config.addExposedHeader("Authorization");
config.addAllowedMethod("POST");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("HEAD");
config.addExposedHeader("Access-Control-Allow-Origin");
config.addExposedHeader("Access-Control-Allow-Headers");
config.addExposedHeader("Access-Control-Allow-Methods");
source.registerCorsConfiguration("/**", config);
return source;
}
启用CORS的Spring代码
/**
* Creates protection rules for specific paths.
*
* @param http security type
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler)
.accessDeniedHandler(accessDeniedHandler)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/", // permit react files
"/index",
"/index.html",
"/favicon.ico",
"/**/*.png",
"/**/*.gif",
"/**/*.svg",
"/**/*.jpg",
"/**/*.html",
"/**/*.css",
"/**/*.map",
"/**/*.js",
"/**/**/*.js",
"*.js",
"/*.js",
"/static/js/*.js",
"/build/static/js/*.js",
"https://at.alicdn.com/**")
.permitAll()
.antMatchers("/api/auth/**")
.permitAll()
.antMatchers("/login", "/imprint", "/profile", "/summary")
.permitAll()
.antMatchers("https://jira03.abc.com/rest/api/2/issue/")
.permitAll()
.antMatchers("/api/user/checkUsernameAvailability", "/api/user/checkEmailAvailability")
.permitAll()
.antMatchers(HttpMethod.GET, "/api/users/user/me")
.permitAll()
.anyRequest().authenticated();
// add own filters
http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
那么我在春季做错什么了吗?我没有在Spring Boot中定义用于获取Jira数据的方法。该方法仅存在于React中。 此外,当我运行react的开发版本时,CORS正在工作。当Spring后端在端口8080上运行时,它在端口3000上运行。它们之间没有CORS错误。仅当我尝试访问外部Jira资源时。可以访问Jira资源,因为我已经在命令行中成功处理了该资源的curl请求。
更新:@Darren
您的方法配置支持不在此范围内。
更新2:白名单理论
我再次尝试从我的程序访问Jira。错误更改为:
Cross origin request blocked:
The cross origin rule prohibits the reading of the external ressource
https://jira03.abc.com/rest/api/2/issue/.
(Reason: CORS header 'Access-Control-Allow-Origin' missing).