从React调用外部资源时发生CORS阻塞

时间:2018-08-07 20:14:34

标签: reactjs spring-boot cors access-control jira-rest-api

我用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

您的方法配置支持不在此范围内。

No supported Method

更新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).

0 个答案:

没有答案