我正在尝试对使用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