-2

I'm trying to set up a login screen on my react app. This provides authorisation to my spring boot backend to provide the data I need displayed. However, I keep getting the following error message from Chrome:

Access to fetch at 'http://localhost:8102/users' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

I've tried the following and they don't seem to work:

In my React app:

Login.js

...
login = () => {
        const user = {username: this.state.username, password: this.state.password};

        fetch(SERVER_URL + "/login", { 
            headers: {
                Accept: 'application/json',
                'Content-Type': 'application/json',
                'Access-Control-Allow-Origin': '*'
            },
            method: 'POST', 
            body: JSON.stringify(user) 
        })
            .then(response => {
                const jwtToken = response.headers.get("Authorization");

                if(jwtToken != null) {
                    sessionStorage.setItem("jwt", jwtToken);
                    sessionStorage.setItem("username", this.state.username);
                    this.setState({ isAuthenticated: true });
                } else {
                    this.setState({ open: true });
                }
            })
            .catch(err => console.error(err));
    }
...

In my App.js:

class App extends Component {
  constructor(props) {
    super(props);

    this.state = { user: "user" };
  }

  componentDidMount() {
    fetch(USER_URL)
      .then((response) => response.json())
      .then((responseData) => { this.setState({ user: responseData._embedded.user }); })
      .catch((err) => console.error("THIS IS A SERIOUS ERROR INDEED!" + err));
  }

  render() {
    return(
      <div className='App'>
        <Login />  
      </div>
    )
  }
}

On my Spring Boot backend:

SecurityConfiguration.java

...
@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().authorizeRequests()
                .antMatchers(HttpMethod.POST, "/login").permitAll()
                .anyRequest().authenticated()
                .and().addFilterBefore(new LoginFilter("/login", authenticationManager()),
                        UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(new AuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    }
...

...
@Bean
    protected CorsConfigurationSource corsConfigurationSource() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

        CorsConfiguration config = new CorsConfiguration();
        config.setAllowedOrigins(Arrays.asList("*"));
        config.setAllowedMethods(Arrays.asList("*"));
        config.setAllowedHeaders(Arrays.asList("*"));
        config.setAllowCredentials(true);
        config.applyPermitDefaultValues();

        source.registerCorsConfiguration("/**", config);

        return source;
    }
...

In my MainController.java1

@RestController
@CrossOrigin
public class MainController {
...

None of that seems to be properly working to get around this CORS issue.

My Server github repository is: AssetRegister-Server

My Client github repository is: AssetRegister-Client

JamieRhys
  • 206
  • 6
  • 24
  • without a github project, debug logs etc. we cant help you. You need to confirm that the CORS configuration is properly loaded. We can't tell since you have only provided the code, and not the surrounding context where you have only placed dots `...` i assume that you have enabled debug logs and read them and confirmed that the CORS configuration is properly loaded before asking here on stack overflow? – Toerktumlare Mar 12 '22 at 18:16
  • Hi @Toerktumlare, I've updated OP with the links to the github repo for you. Sorry for the actual post – JamieRhys Mar 12 '22 at 22:31

1 Answers1

0

To make sure that spring security actually uses CORS, you have to actually enable it.

Its not enough to just register a configuration as a @Bean.

you enable CORS in you security config like this:

 http.csrf().disable()
     .cors()
     .and()
     .authorizeRequests()

Other things to point out in your code base:

  • @CrossOrigin can be removed since you are are defining CORS using spring security.
  • You have implemented a some sort of custom login solution when spring security already has something called formLogin all you need to do is enable formLogin and then send the data using javascript fetch as form data fetch and form data and then you can remove your entire custom login. Writing custom login as you have done is bad practice, and if you would submit this code in production or to learn, you are learning very bad practices.
  • Spring security comes already with a JWT library built in called Nimbus, so there is no need to pull in a different one as you have done.
  • Using JWTs as sessions comes with security risks and there are several blogs talking about that you should not use them as sessions json-web-tokens-jwt-are-dangerous-for-user-sessions Why JWTs Suck as Session Tokens You should think about this before using JWTs as session tokens. The way they you have them implemented now you have no possibility of revoking tokens so if someone steals a token, then you cant stop them from using it maliciously until it times out.
  • Benefits by using formLogin is that you can use the authenticationSuccess handler to return a session/token
.formLogin(formLoginSpec -> formLoginSpec.loginPage("/login")
                        .authenticationFailureHandler(new AuthenticationFailureHandler())
                        .authenticationSuccessHandler(new AuthenticationSuccessHandler())

So what im trying to say is that if you are following a tutorial etc. Then it is very out of date, or it has no idea about what actually exists in spring security. And i recommend that you look into the official documentation. Its very good.

Toerktumlare
  • 12,548
  • 3
  • 35
  • 54
  • I've enabled cors using the original method above but I'm still getting the same error from the browser. Also, in term of the login process, I've used Full Stack Development With Spring Boot 2.0 and React. However, I'm not overly worried about security per sae as this will be used behind a firewall and not actually see the outside world. I'm just using the login so that I can keep track of who is doing what essentially. – JamieRhys Mar 13 '22 at 12:20
  • i checked out your code, and debugged it. Your configuration was not picked up because your code did not enable cors. I enabled cors and the CorsFilter picked up your configuration. If its still not working, then i cant help you, unless you actually post what error you are getting. Because the previous error message you have posted, says that no header was present. After my debugging i could CLEARLY see that the header was present after i enabled CORS. Without an error message or the ability for me to reproduce, then good luck – Toerktumlare Mar 13 '22 at 14:09
  • also `I'm not overly worried about security per sae as this will be used behind a firewall and not actually see the outside world` is a poor defence to building bad security. If someone gains access to your network through a reverse shell, your fw is not worth anything. – Toerktumlare Mar 13 '22 at 14:12