我正在尝试将Spring Security身份验证添加到我的完整堆栈Web应用程序中,该应用程序存在于Java-Spring Boot后端中,该后端使用JPA与数据库进行通信并从React前端接收HTTP请求。我遇到了一个问题,即一旦将身份验证添加到后端方法中,尝试调用它们时,前端就会出现CORS错误。我尝试过发送没有授权标头的请求,以及使用编码的用户名和密码发送请求。没有授权标头,我会得到错误:
CORS策略已阻止从原始地址“ http:// localhost:3000”访问“ http:// localhost:8080 / admin”处的XMLHttpRequest:在该服务器上不存在“ Access-Control-Allow-Origin”标头请求的资源。
有了标题,标题中就会出现错误,完整如下:
CORS策略已阻止从来源“ http:// localhost:3000”访问“ http:// localhost:8080 / admin”处的XMLHttpRequest:对预检请求的响应未通过访问控制检查:否'请求的资源上存在Access-Control-Allow-Origin标头。
我已经尝试过针对类似问题提供的多种解决方案,从修改configure方法到向类添加注册表bean不等。不过似乎对我没有任何帮助。还有其他想法吗?
请参阅下面的最新代码: SecurityConfiguration:
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
MyUserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors();
http.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers("/admin").hasRole("ADMIN")
.antMatchers("/user").hasAnyRole("ADMIN", "USER")
.antMatchers("/").permitAll()
.and().formLogin();
}
@Bean
public PasswordEncoder getPasswordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
MyUserDetails:
@Service
public class MyUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
// Optional<User> user = userRepository.findByUserName(userName);
//
// user.orElseThrow(() -> new UsernameNotFoundException("Not found: " + userName));
//
// return user.map(MyUserDetails::new).get();
User user = new User();
user.setUserName("John");
user.setPassword("pass");
user.setActive(true);
user.setRoles("ROLE_ADMIN");
return new MyUserDetails(user);
}
}
MyUserDetails:
public class MyUserDetails implements UserDetails {
private String userName;
private String password;
private boolean active;
private List<GrantedAuthority> authorities;
public MyUserDetails(User user) {
this.userName = user.getUserName();
this.password = user.getPassword();
this.active = user.isActive();
this.authorities = Arrays.stream(user.getRoles().split(","))
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return userName;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return active;
}
}
用户:
public class User {
private int id;
private String userName;
private String password;
private boolean active;
private String roles;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
public String getRoles() {
return roles;
}
public void setRoles(String roles) {
this.roles = roles;
}
}
HomeController:
@CrossOrigin("localhost")
@RestController
public class HomeController {
@GetMapping("/")
public String home() {
return ("<h1>Welcome</h1>");
}
@GetMapping("/user")
public String user() {
return ("<h1>Welcome User</h1>");
}
@GetMapping("/admin")
public String admin() {
return ("<h1>Welcome Admin</h1>");
}
}
最后,我的React组件包括axios请求:
class Demo extends React.Component{
signIn(){
axios.get("http://localhost:8080/admin", {
headers : {
'Authorization' : 'Basic ' + window.btoa(document.getElementById("username").value + ':' + document.getElementById("password"))
}}).then(response => {
console.log(response.data);
}
)
}
render(){
return(
<div>
{/*<TradeOverview />*/}
{/*<NewTradeForm />*/}
<input id="username"/>
<input id="password" type="password"/>
<button onClick={this.signIn}>Sign in</button>
</div>
) ;
}
}
export default Demo;
快速说明:我目前正在对JPA实现进行硬编码,因为这只是一个没有任何数据库的演示。