Access-Control-Allow-Origin问题,无法使用Spring Security保护POST到API端点

时间:2017-09-24 20:18:04

标签: spring reactjs spring-security cors fetch-api

我正在尝试对使用Spring Security保护的API端点进行POST。此POST的目的是传递凭据(用户名和密码)。我很肯定正确地完成安全,因为我已经测试了它而没有从前端发布,一切正常。

我的前端是用React编写的,我正在使用fetch库来发布登录凭据。第一次提取工作正常(它调用所有用户都可以使用的端点),但第二次提取失败并显示消息:

  

Fetch API无法加载http://localhost:8080/rest/book/anna/all。   对预检请求的响应未通过访问控制检查:否   请求中存在“Access-Control-Allow-Origin”标头   资源。因此不允许来源“http://localhost:8888”   访问。响应具有HTTP状态代码403.如果是不透明的响应   满足您的需求,将请求的模式设置为'no-cors'来获取   CORS禁用的资源。

问题是我在该端点上启用了CORS。所以,我的问题是;我做错了什么,以便我一直收到403以下的错误?首先,我在GET上获得200,在OPTION上获得403,而我期望在POST上获得200.

我正在进行获取的反应类:

import React, {Component} from 'react';
import fetch from 'isomorphic-fetch';

class FAQ extends Component {
    componentDidMount() {
        const API_ENDPOINT = "http://localhost:8080/rest/book/all";
        fetch(API_ENDPOINT).then((response) => {
            console.log('response');
            console.log(response);
            console.log('after response');
            return response.json().then((json) => {
                console.log('json');
                console.log(json);
            })
        })
    }

    postLoginData(){
        fetch('http://localhost:8080/rest/book/anna/all', {
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json'
            },
            credentials: 'include',
            method: 'POST',
            body: JSON.stringify({
                username: 'c',
                password: 'd',
            })
        }).then(response => console.log(response))
    }

    render() {
        return (
            <div>
                <p>Here some Frequently Asked Questions will be displayed.</p>
                {console.log('FAQ')}
                { this.props.children }
                <button type="button" onClick={this.postLoginData}>
                    post
                </button>
            </div>
        )
    }
}

export default FAQ;

SecurityConfig

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
@EnableJpaRepositories(basePackageClasses = UsersRepository.class)
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomUserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService)
                .passwordEncoder(getPasswordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .cors()
                .and()
                .authorizeRequests()
                .antMatchers("**/anna/**").authenticated()
                .anyRequest().permitAll()
                .and()
                .formLogin().permitAll();

        http
                .logout()
                .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                .logoutSuccessUrl("/rest/author/all");
    }

    private PasswordEncoder getPasswordEncoder() {
        return new PasswordEncoder() {
            @Override
            public String encode(CharSequence charSequence) {
                return charSequence.toString();
            }

            @Override
            public boolean matches(CharSequence charSequence, String s) {
                return true;
            }
        };
    }
}

被叫控制器:

package com.shareabook.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;


@RestController
@RequestMapping("/rest/book")
public class BookController {
    @CrossOrigin
    @GetMapping(value = "/all")
    public String hello() {
        return "hello book controller all";
    }

    @CrossOrigin
    @PreAuthorize("hasAnyRole('ROLE_ADMIN')")
    @GetMapping(value = "/anna/all")
    public String securedHello() {
        return "hello secured book controller all";
    }
}

在评论中建议更改后,我停止收到CORS错误,但仍然有403错误。我不知道为什么,因为我确信凭证是正确的,并且在服务器上手工记录时它完美地工作。

我的RequestHeader:

POST /login HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Content-Length: 31
Accept: application/json
Origin: http://localhost:8888
User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36
Content-Type: application/json
Referer: http://localhost:8888/FAQ
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.8
Cookie: JSESSIONID=9FA83D5C49B7351B8DA630B2617E49CA

ResponseHeader

HTTP/1.1 403
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Access-Control-Allow-Origin: http://localhost:8888
Vary: Origin
Access-Control-Allow-Credentials: true
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Tue, 26 Sep 2017 17:34:23 GMT

0 个答案:

没有答案