60
votes

I am newbie in spring boot rest services. I have developed some rest api in spring boot using maven project.

I have successfully developed Get and Post Api. My GET Method working properly in postman and mobile. when i am trying to hit post method from postman its working properly but from mobile its gives 403 forbidden error.

This is my Configuration:

spring.datasource.url = jdbc:mysql://localhost/sampledb?useSSL=false
spring.datasource.username = te
spring.datasource.password = test
spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MySQL5InnoDBDialect
Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = update

Please Suggest me how to solve error.

enter image description here

5
Are you sending any header with postman? I think that you are sending a token in order to authenticate the request. Are you sending this token on POST from your mobile device? - desoss
Please add details of your spring-boot configuration. - Jannik Weichert
i am sending only Content type from postman and mobile @desoss - Harshal Deshmukh
please attach the logs, spring has surprisingly readable error messages in logs ;) - Jan Ossowski
This is my configurations: #spring.datasource.url = jdbc:mysql://192.168.4.2/maha?useSSL=false #spring.datasource.username = test #spring.datasource.password = test@123 # # ### Hibernate Properties ## The SQL dialect makes Hibernate generate better SQL for the chosen database #spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect # ## Hibernate ddl auto (create, create-drop, validate, update) #spring.jpa.hibernate.ddl-auto = update @JannikWeichert - Harshal Deshmukh

5 Answers

164
votes

you have to disable csrf Protection because it is enabled by default in spring security: here you can see code that allow cors origin.

import org.springframework.context.annotation.Bean;
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.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{

    @Override
    protected void configure(HttpSecurity http) throws Exception{
        http.cors().and().csrf().disable();
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("*"));
        configuration.setAllowedHeaders(Arrays.asList("*"));
        configuration.setAllowCredentials(true);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

}
7
votes

Possible causes:

  1. Requests done from postman are different to the one done from mobile (uri, method, headers)
  2. Invalid token
  3. CORS (read something about it, google is full of articles) add @CrossOrigin annotation to your controller.
  4. mobile app is doing an OPTION request before performing the POST, and you block OPTION requests. If also from postman the OPTION requests are blocked, add the property spring.mvc.dispatch-options-request=true. Moreover, in case you are using spring security, you have to explicitly allow OPTION requests also for it.
1
votes

CSRF is enabled by default in Spring Security. Having this enabled ensures a 403 error on HTTP requests that would change (object) states. For more information please visit: https://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/html5/#csrf

It is possible to disable CSRF in the Spring Security. However, it is enabled by default (convention over configuration) and for a good reason. This is also explained in the link provided to Spring's Security.

A working example, using Thymeleaf, might be:

HTML

<head>
    <meta name="_csrf" th:content="${_csrf.token}"/>
    <meta name="_csrf_header" th:content="${_csrf.headerName}"/>
</head>

JS

function postExample() {
    let token = $("meta[name='_csrf']").attr("content");
    let header = $("meta[name='_csrf_header']").attr("content");

    let data = {username: "", password: "", firstname: "", lastname: ""};

    // Object key string interpolation by {[header]:token} works with ES6
    fetch(window.location+"/addnote", {
        method:"POST",
        headers: {
            [header]: token,
            "charset": "UTF-8",
            "Content-Type": "application/json"
        },
        body: JSON.stringify(data)
    }).then(res => console.log(res)).catch(err => console.log(err))
}
1
votes

In Spring Security Cross-site check is by default enable, we need to disable it by creating a separate class to stop cross-checking.

package com.baba.jaxws;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter{

     @Override
    //we have stopped the csrf to make post method work
        protected void configure(HttpSecurity http) throws Exception{
            http.cors().and().csrf().disable();
        }
}
0
votes

To build on the accepted answer

Many HTTP client libraries (eg Axios) implicitly set a Content-Type: JSON header for POST requests. In my case, I forgot to allow that header causing only POSTS to fail.

@Bean
CorsConfigurationSource corsConfigurationSource() {
    ...
    configuration.addAllowedHeader("Content-Type"); // <- ALLOW THIS HEADER 
    ...
}