You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go语言中如何合并Gorilla Mux的认证与非认证路由?

合并Gorilla Mux的认证与非认证路由

我有如下Go代码,包含两个Gorilla Mux路由:一个非认证路由(r),另一个是通过Alice中间件包装的认证路由(chain)。希望将两个路由合并后提供服务。

package main

import (
    "ekart.com/authentication_service/models"

    "fmt"
    "log"
    "net/http"

    "github.com/gorilla/mux"
    "github.com/justinas/alice"
)

func main() {
    var JSON_SECRET []byte = []byte("TZWfMhBEuyzsc2e52wQQaDxfBriktka9GR4BhBtH9PhXi6XHwyaaaUyxBc-yd1RtYKsiFAGXZcBJuQ6ML5UGBEEx72Qhw6Q-192msUDwMHxT3Scz5wWnk--Bp8wotvu7FS2-v88cvC52e1lfG8mr60dGu7kg-jzcRa5cDTfR4KMQIAD6lO1H3J6f48u46gLjQtzOLPH9yjx0mqVtGWmaizGMQE7NdrhHH5ZlMuuj-A6lZRjf2VZKxUiFFWmfnVMhPVh-wpOybMaFzhUjm-RWXQ-E6cCeI-sBzcu5ZJ8aZVnYPc1Inc5RJ9R5rKQblctxHt5QCYlxiFHb63aO36ZS0Q")
    var DSN string = "root:toor@tcp(localhost:3306)/ekart_auth?charset=utf8&parseTime=True&loc=Local"
    app := Config{secret: JSON_SECRET}
    app.NewDatabaseConnection(DSN)
    app.DB.AutoMigrate(&models.User{})

    r := mux.NewRouter()
    r.HandleFunc("/login", app.Login).Methods("POST")
    r.HandleFunc("/register", app.Register).Methods("POST")
    
    authmux := mux.NewRouter()
    authmux.HandleFunc("/onlyauth", app.OnlyIfAuthenticated).Methods("GET")
    chain := alice.New(app.Authenticate).Then(authmux)

    log.Print(fmt.Sprintf("Starting Server on port %d", 8080))
    log.Fatal(http.ListenAndServe(fmt.Sprintf(":%v", 8080), r))

}

我尝试过合并路由的方法但未成功,也试过Gorilla Mux官方文档中的路径前缀方式:

s := r.PathPrefix("/auth").Subrouter()
s.HandleFunc("/", chain.ServeHTTP)

同样无效。最好无需创建子路径,若必须创建也可接受。


解决方案

方案1:无需子路径,给单个认证接口添加中间件

直接在主路由上为需要认证的接口单独应用Alice中间件,无需额外创建路由:

func main() {
    // ... 省略数据库初始化等代码 ...

    r := mux.NewRouter()
    // 非认证接口
    r.HandleFunc("/login", app.Login).Methods("POST")
    r.HandleFunc("/register", app.Register).Methods("POST")

    // 为需要认证的接口包装中间件
    authChain := alice.New(app.Authenticate)
    r.Handle("/onlyauth", authChain.ThenFunc(app.OnlyIfAuthenticated)).Methods("GET")

    log.Print("Starting Server on port 8080")
    log.Fatal(http.ListenAndServe(":8080", r))
}

方案2:无需子路径,给一组认证接口统一加中间件

如果有多个需要认证的接口,可以创建主路由的子路由,然后给子路由绑定认证中间件:

func main() {
    // ... 省略数据库初始化等代码 ...

    r := mux.NewRouter()
    // 非认证接口
    r.HandleFunc("/login", app.Login).Methods("POST")
    r.HandleFunc("/register", app.Register).Methods("POST")

    // 创建子路由并应用认证中间件
    authSubrouter := r.PathPrefix("").Subrouter()
    authSubrouter.Use(func(next http.Handler) http.Handler {
        return app.Authenticate(next)
    })
    // 所有子路由下的接口都会经过认证
    authSubrouter.HandleFunc("/onlyauth", app.OnlyIfAuthenticated).Methods("GET")
    // 可添加更多认证接口
    // authSubrouter.HandleFunc("/profile", app.GetProfile).Methods("GET")

    log.Print("Starting Server on port 8080")
    log.Fatal(http.ListenAndServe(":8080", r))
}

方案3:接受子路径,正确挂载认证路由

如果可以接受子路径,之前的错误在于使用了HandleFunc,正确的做法是用Handler方法将认证路由挂载到主路由:

func main() {
    // ... 省略数据库初始化等代码 ...

    r := mux.NewRouter()
    // 非认证接口
    r.HandleFunc("/login", app.Login).Methods("POST")
    r.HandleFunc("/register", app.Register).Methods("POST")

    // 认证路由
    authmux := mux.NewRouter()
    authmux.HandleFunc("/onlyauth", app.OnlyIfAuthenticated).Methods("GET")
    chain := alice.New(app.Authenticate).Then(authmux)

    // 正确挂载认证路由到子路径
    r.PathPrefix("/auth").Handler(chain)

    log.Print("Starting Server on port 8080")
    log.Fatal(http.ListenAndServe(":8080", r))
}

此时访问认证接口的路径为/auth/onlyauth。


内容的提问来源于stack exchange,提问作者Sushant

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 16:55:22