rs / cors

Go net/http configurable handler to handle CORS requests
MIT License
2.64k stars 220 forks source link

GIN: cannot use CORS middleware with router groups #102

Closed samber closed 5 months ago

samber commented 4 years ago

I need different CORS settings in 2 groups. This middleware works only at "router" level.

The issue can be reproduced with the following code:

package main

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

func ctrl(c *gin.Context) {
    c.JSON(200, gin.H{
        "status": "ok",
    })
}

func main() {
    router := gin.New()

    // first group with "/1" prefix
    group1 := router.Group("/1")
    group1.Use(cors.New(cors.Options{
        AllowedOrigins:   []string{"http://a.b.c"},
        AllowedMethods:   []string{"GET", "HEAD", "OPTIONS",},
        AllowedHeaders:   []string{"Origin", "Content-Type"},
        AllowCredentials: false,
    }))
    group1.GET("/1", ctrl)

    // second group with "/2" prefix
    group2 := router.Group("/2")
    group2.Use(cors.New(cors.Options{
        AllowedOrigins:   []string{"http://d.e.f"},
        AllowedMethods:   []string{"GET", "HEAD", "OPTIONS", "POST", "PUT", "PATCH", "DELETE"},
        AllowedHeaders:   []string{"Origin", "Authorization", "Cookie", "Content-Type"},
    }))
    group2.GET("/2", ctrl)

    router.Run(":8080")
}

Adding the "OPTIONS" catch-all route doesn't change anything.

group1.OPTIONS("", func(c *gin.Context) {
    c.AbortWithStatus(204)
})

You can test it with this client.

Any idea how to solve this?

sno6 commented 4 years ago

Any luck @samber ?

mjubil1 commented 4 years ago

@samber I am also facing the same issue.

RubenGarcia commented 3 years ago

I think cors runs first, when the connection is established, and does not know anything about the endpoint itself ("1/*") so it cannot be used at the Group granularity level.

sify21 commented 2 years ago

I had to add an options mapping to each endpoint

OhBonsai commented 2 years ago

web browser will send OPTIONS to check CORS policy before request. In common secranio. router only define specific method like get, post. SO when server recieve options method. It will reconginze this route is not registed. then code run into default middleware

// Use attaches a global middleware to the router. ie. the middleware attached though Use() will be
// included in the handlers chain for every single request. Even 404, 405, static files...
// For example, this is the right place for a logger or error management middleware.
func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
    engine.RouterGroup.Use(middleware...)
    engine.rebuild404Handlers()
    engine.rebuild405Handlers()
    return engine
}

use cors middlware in default group!!!

jub0bs commented 5 months ago

The root cause of this issue lies in Gin's router, not in rs/cors. See https://github.com/gin-gonic/gin/issues/531.

@rs I think you could close this issue.

seerhut commented 6 days ago

As the preflight OPTIONS request cannot reach the routergroup's handler chain if there is no valid handler for this OPTIONS request, I use a wrapper to make sure every GET/POST has a paired OPTIONS handler. Then I can give every group different CORS policies.

v1 := r.Group("/api/v1")
v1.Use(cors.New(cors.Config{...}))
addHandler(pri, "POST", "/updateWord", controller.UpdateWord)
pp := r.Group("/api/ext")
pp.Use(cors.New(cors.Config{...}))
addHandler(pri, "GET", "/getAllWords", controller.ListAllWordsForUser)

func addHandler(r *gin.RouterGroup, method string, path string, handler func(c *gin.Context)) {
    if method != "OPTIONS" {
        r.Handle(method, path, handler)
        r.OPTIONS(path, func(c *gin.Context) {})
    }else{
        r.OPTIONS(path, handler)
    }
}
jub0bs commented 6 days ago

@seerhut method != "OPTIONS" is too restrictive: not all OPTIONS requests are preflight requests; see https://jub0bs.com/posts/2023-02-08-fearless-cors/#4-categorise-requests-correctly

seerhut commented 5 days ago

@seerhut method != "OPTIONS" is too restrictive: not all OPTIONS requests are preflight requests; see https://jub0bs.com/posts/2023-02-08-fearless-cors/#4-categorise-requests-correctly

Thx, great article for summary!