gin-contrib / cors

Official CORS gin's middleware
https://gin-gonic.github.io/gin/
MIT License
1.76k stars 182 forks source link

Rejected OPTIONS request when OPTIONS is configured in cors. #78

Open ErikDz opened 3 years ago

ErikDz commented 3 years ago

Description

Having cors configurated in order to accept CORS requests, when sending an multipart/form-data, the following appears: Access to XMLHttpRequest at 'http://localhost:8080/add_project' from origin 'http://localhost:3000' has been blocked by CORS policy: Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response.

How to reproduce

package main

import (
    "github.com/gin-gonic/gin"
        "github.com/gin-contrib/cors"
)

func add_project(c *gin.Context) {
    c.Header("Access-Control-Allow-Origin", "*")

    // Connection to the database
    db := initDB()

    var newProject project

    claims, err := encryption.GetClaims(encryption.GetToken(c))
    if err != nil {
        c.JSON(http.StatusBadRequest, nil)
        return
    }

    if err := c.BindJSON(&newProject); err != nil {
        return
    }
    if claims["username"] == "erikdz" {
        statement, _ := db.Prepare("INSERT INTO projects (name, date, state, abandoned, description, image) VALUES (?, ?, ?, ?, ?, ?)")
        statement.Exec(newProject.Name, newProject.Date, newProject.State, newProject.Abandoned, newProject.Description, newProject.Image)
        c.JSON(http.StatusAccepted, nil)
    } else {
        c.JSON(http.StatusUnauthorized, nil)
    }
    // Close connection database
    defer db.Close()
}

func main() {
    router := gin.Default()
    corsConfig := cors.DefaultConfig()
    corsConfig.AllowOrigins = []string{"http://localhost:3000"}
    // To be able to send tokens to the server.
    corsConfig.AllowCredentials = true
    // OPTIONS method for ReactJS
    corsConfig.AddAllowMethods("OPTIONS")
    router.Use(cors.New(corsConfig))

    router.POST("/add_project", add_project)

    router.Run("localhost:8080")

}

React code:

   if (formIsValid){
    var formData = new FormData();

     formData.append('file', this.state.image)
     formData.append('data', {
                              name:this.state.name,
                              state:this.state.state,
                              date: this.state.date,
                              description: this.state.description,
                              abandoned: this.state.abandoned
                            })
    axios({
      method: "post",
      url: process.env.REACT_APP_API_DOMAIN + "/add_project",
      data: formData,
      headers: { "Content-Type": "multipart/form-data", "Authorization" : `Bearer ${this.state.jwttoken}` },
    })
      .then(function (response) {
        //handle success
        console.log(response);
      })
      .catch(function (response) {
        //handle error
        console.log(response);
      });
   }

Expectations

200 StatusAccepted

Actual result

Access to XMLHttpRequest at 'http://localhost:8080/add_project' from origin 'http://localhost:3000' has been blocked by CORS policy: Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response.

$ curl -i -X OPTIONS http://localhost:8080/add_project
   -H "Access-Control-Request-Method: POST"
   -H "Access-Control-Request-Headers: content-type"
   -H "Origin: https://reqbin.com"

HTTP/1.1 403 Forbidden
Date: Sun, 01 Aug 2021 09:45:18 GMT
Content-Length: 0

404 page not found

Environment

go version: go version go1.13.8 linux/amd64 gin version (or commit ref): latest operating system: ubuntu 20.04

envisioncheng commented 2 years ago

change and try

1.test OPPTIONS curl -X OPTIONS http://localhost:8080/add_project //check? delete -i -H "Access-Control-Request-Method: POST" -H "Access-Control-Request-Headers: content-type" -H "Origin: http://localhost:3000" //check? set incorrect Origin

2.test POST curl -i -X POST http://localhost:8080/add_project
-H "Access-Control-Request-Method: POST" -H "Access-Control-Request-Headers: content-type" -H "Origin: http://localhost:3000" //check? set correct Origin -d '{ "name": "test" }' //this is jon,you need change this for multipart/form-data correct.

jub0bs commented 9 months ago

Working as expected. Your issue stems from a misunderstanding of how CORS works. The Access-Control-Allow-Credentials header is only relevant for credentials that are managed (and automatically added to requests) by the browser, not by the client.

If the client (as opposed to the browser) sets a request header named Authorization, then the server must list that name in its Access-Control-Allow-Headers response header. More details in this Stack Overflow answer.

Since that header name is not allowed by this library's default config, you need to explicitly allow it.

Besides, you shouldn't manually set CORS response headers in addition to using a CORS middleware.

approached commented 4 months ago

Use this:

    // cors disable
    corsConfig := cors.DefaultConfig()
    corsConfig.AddAllowHeaders("Authorization") // Add Authorization to the list of allowed headers
    corsConfig.AllowAllOrigins = true
    r.Use(cors.New(corsConfig))
jub0bs commented 4 months ago

@approached That first comment is confusing. Instead, you must have meant

// enable CORS