From b92ca64cf8f54c3b9025ceea80f243072da51db9 Mon Sep 17 00:00:00 2001 From: kingecg Date: Sat, 14 Jun 2025 15:16:48 +0800 Subject: [PATCH] =?UTF-8?q?refactor(admin):=20=E9=87=8D=E6=9E=84=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E6=A8=A1=E5=9D=97=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 引入 Gin 框架替换原有的服务器 Mux - 重写 API 路由处理函数,适应 Gin 框架 - 添加 JWT 认证和基本认证的中间件 - 优化登录逻辑,支持 JWT 令牌生成和验证 - 更新相关依赖库版本 --- admin/admin.go | 164 ++++++++++++++++++++++++------------------- admin/login.go | 135 ++++++++++++++++++++++++++++------- go.mod | 31 +++++--- go.sum | 53 ++++++++++++++ server/middleware.go | 23 +++++- 5 files changed, 295 insertions(+), 111 deletions(-) diff --git a/admin/admin.go b/admin/admin.go index 95fdced..a47a52a 100644 --- a/admin/admin.go +++ b/admin/admin.go @@ -3,128 +3,148 @@ package admin import ( "errors" "net/http" - "os" "runtime" "git.pyer.club/kingecg/gohttpd/model" "git.pyer.club/kingecg/gohttpd/server" + "github.com/gin-gonic/gin" // 添加Gin框架导入 ) type RunStatus struct { Goroutines int `json:"goroutines"` } -func about(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - w.Write([]byte("About Page")) +func about(c *gin.Context) { + c.Writer.WriteHeader(http.StatusOK) + c.Writer.Write([]byte("About Page")) } -func setConfig(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() +func setConfig(c *gin.Context) { + ctx := c.Request.Context() ctxData := ctx.Value(server.RequestCtxKey("data")).(map[string]interface{}) data, ok := ctxData["data"] if !ok { - w.WriteHeader(http.StatusBadRequest) + c.Writer.WriteHeader(http.StatusBadRequest) return } t := data.(model.HttpServerConfig) if t.Name == "admin" { - w.WriteHeader(http.StatusForbidden) + c.Writer.WriteHeader(http.StatusForbidden) resp := server.NewErrorResult(errors.New("不能通过api设置管理服务器")) - w.Write(resp) - } - err := model.SetServerConfig(&t) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - w.Write(server.NewErrorResult(err)) + c.Writer.Write(resp) return } - defer func() { - os.Exit(0) - }() - w.WriteHeader(http.StatusOK) - w.Write(server.NewSuccessResult(t)) + er := model.SetServerConfig(&t) + if er != nil { + c.Writer.WriteHeader(http.StatusBadRequest) + c.Writer.Write(server.NewErrorResult(er)) + return + } + c.Writer.WriteHeader(http.StatusOK) + c.Writer.Write(server.NewSuccessResult(t)) } -func getServerConfigure(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - ctxData := ctx.Value(server.RequestCtxKey("data")).(map[string]interface{}) - id, ok := ctxData["id"] - if ok { - if id.(string) == "admin" { - w.WriteHeader(http.StatusForbidden) +func getServerConfigure(c *gin.Context) { + // ctx := c.Request.Context() + // get url param + // g. + //ctxData := ctx.Value(server.RequestCtxKey("data")).(map[string]interface{}) + id := c.Param("name") + if id != "" { + if id == "admin" { + c.Writer.WriteHeader(http.StatusForbidden) resp := server.NewErrorResult(errors.New("不能通过api获取管理服务器配置信息")) - w.Write(resp) + c.Writer.Write(resp) return } - data := model.GetServerConfig(id.(string)) - /// configContent, _ := json.Marshal(data) - w.WriteHeader(http.StatusOK) - w.Write(server.NewSuccessResult(data)) + data := model.GetServerConfig(id) + c.Writer.WriteHeader(http.StatusOK) + c.Writer.Write(server.NewSuccessResult(data)) } else { - http.NotFound(w, r) + http.NotFound(c.Writer, c.Request) } } -func getStatus(w http.ResponseWriter, r *http.Request) { - //获取当前进程的goroutines数量 +func getStatus(c *gin.Context) { + runtime := runtime.NumGoroutine() ret := RunStatus{ - Goroutines: runtime.NumGoroutine(), + Goroutines: runtime, } - - w.WriteHeader(http.StatusOK) - w.Write(server.NewSuccessResult(ret)) + c.Writer.WriteHeader(http.StatusOK) + c.Writer.Write(server.NewSuccessResult(ret)) } -func stop(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - ctxData := ctx.Value(server.RequestCtxKey("data")).(map[string]interface{}) - name, ok := ctxData["name"] - if ok { - serverConf := model.GetServerConfig(name.(string)) - server.StopServer(name.(string), serverConf.Port) - w.WriteHeader(http.StatusOK) +func stop(c *gin.Context) { + // ctx := c.Request.Context() + // ctxData := ctx.Value(server.RequestCtxKey("data")).(map[string]interface{}) + name := c.Param("name") + if name != "" { + serverConf := model.GetServerConfig(name) + server.StopServer(name, serverConf.Port) + c.Writer.WriteHeader(http.StatusOK) data := "stopped" - w.Write(server.NewSuccessResult(data)) + c.Writer.Write(server.NewSuccessResult(data)) return } - http.NotFound(w, r) + http.NotFound(c.Writer, c.Request) } -func start(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - ctxData := ctx.Value(server.RequestCtxKey("data")).(map[string]interface{}) - name, ok := ctxData["name"] - if ok { - serverConf := model.GetServerConfig(name.(string)) - server.StartServer(name.(string), serverConf.Port) - w.WriteHeader(http.StatusOK) +func start(c *gin.Context) { + name := c.Param("name") + if name != "" { + serverConf := model.GetServerConfig(name) + server.StartServer(name, serverConf.Port) + c.Writer.WriteHeader(http.StatusOK) data := "started" - w.Write(server.NewSuccessResult(data)) + c.Writer.Write(server.NewSuccessResult(data)) return } } -var AdminServerMux *server.RestMux +var AdminServerMux *gin.Engine +// InitAdminApi 初始化管理API路由 +// 参数: +// +// conf: 指向HttpServerConfig的指针,包含服务器配置信息。 +// +// 返回值: +// +// 无直接返回值,初始化全局AdminServerMux变量。 func InitAdminApi(conf *model.HttpServerConfig) { + // 创建Gin路由器实例 + router := gin.Default() - AdminServerMux = server.NewRestMux("/api") + // 根据认证类型添加中间件 if conf.AuthType == "jwt" { - AdminServerMux.Use(server.JwtAuth) + router.Use(jwtAuth) // 使用JWT认证中间件 } else if conf.AuthType == "basic" { - AdminServerMux.Use(server.BasicAuth) + router.Use(ginBashiAuth) // 使用基础认证中间件 } - // AdminServerMux.Use(server.JwtAuth) - AdminServerMux.HandleFunc("GET", "/about", http.HandlerFunc(about)) - postConfigRoute := AdminServerMux.HandleFunc("POST", "/config", http.HandlerFunc(setConfig)) - postConfigRoute.Add(server.Parse[model.HttpServerConfig]) - AdminServerMux.HandleFunc("GET", "/config/:id", http.HandlerFunc(getServerConfigure)) - AdminServerMux.HandleFunc("GET", "/status", http.HandlerFunc(getStatus)) - AdminServerMux.HandleFunc("Post", "/stop/:name", http.HandlerFunc(stop)) - AdminServerMux.HandleFunc("Post", "/start/:name", http.HandlerFunc(start)) - loginRoute := AdminServerMux.HandleFunc("POST", "/login", http.HandlerFunc(login)) - loginRoute.Add(server.Parse[LoginModel]) - // AdminServerMux.Use(server.BasicAuth) + + // 注册路由处理函数 + api := router.Group("/") + { + api.GET("about", about) + + configGroup := api.Group("config") + { + configGroup.POST("", setConfig) + configGroup.GET(":name", getServerConfigure) + } + + api.GET("status", getStatus) + + serverGroup := api.Group("server") + { + serverGroup.POST("stop/:name", stop) + serverGroup.POST("start/:name", start) + } + + api.POST("login", login) + } + + // 将路由器赋值给全局变量 + AdminServerMux = router } diff --git a/admin/login.go b/admin/login.go index a05f72f..5f59337 100644 --- a/admin/login.go +++ b/admin/login.go @@ -3,11 +3,14 @@ package admin import ( "encoding/hex" "errors" + "fmt" "net/http" + "strings" "time" "git.pyer.club/kingecg/gohttpd/model" "git.pyer.club/kingecg/gohttpd/server" + "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt/v5" ) @@ -16,46 +19,63 @@ type LoginModel struct { Encrypt string `json:"password"` } -func login(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - ctxData := ctx.Value(server.RequestCtxKey("data")).(map[string]interface{}) - data, ok := ctxData["data"] - if !ok { - w.WriteHeader(http.StatusBadRequest) +// login 处理用户登录请求,验证凭证并生成会话令牌。 +// 参数: +// +// w: HTTP响应写入器,用于返回响应状态和数据。 +// r: 指向HTTP请求的指针,包含请求上下文和数据。 +// +// 返回值: +// +// 无直接返回值,通过w写入HTTP响应。 +func login(c *gin.Context) { + // 从请求上下文中获取请求数据 + // ctx := c.Request.Context() + // ctxData := ctx.Value(server.RequestCtxKey("data")).(map[string]interface{}) + // data, ok := ctxData["data"] + loginModel := LoginModel{} + // 绑定请求体到LoginModel结构体 + if err := c.ShouldBindJSON(&loginModel); err != nil { + c.Writer.WriteHeader(http.StatusBadRequest) + c.Writer.Write(server.NewErrorResult(err)) return } - t := data.(LoginModel) - if t.Username == "admin" { - decryptText, _ := Decrypt(t.Encrypt) + + // 验证是否为管理员账号 + if loginModel.Username == "admin" { + // 解密密码并验证与配置文件中密码是否匹配 + decryptText, _ := Decrypt(loginModel.Encrypt) if decryptText == model.GetConfig().Admin.Password { - token, err := GenerateToken(t.Username) + // 生成JWT令牌 + token, err := GenerateToken(loginModel.Username) if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write(server.NewErrorResult(err)) + c.Writer.WriteHeader(http.StatusInternalServerError) + c.Writer.Write(server.NewErrorResult(err)) return } - http.SetCookie(w, &http.Cookie{ - Name: "token", - Value: token, - Path: "/", - // HttpOnly: true, - // Secure: true, + // 设置认证Cookie并返回成功响应 + cookie := &http.Cookie{ + Name: "token", + Value: token, + Path: "/", SameSite: http.SameSiteStrictMode, Expires: time.Now().Add(time.Hour * 24 * 7), - }) - w.WriteHeader(http.StatusOK) - - w.Write(server.NewSuccessResult("Login success")) + } + c.Writer.Header().Set("Set-Cookie", cookie.String()) + c.Writer.WriteHeader(http.StatusOK) + c.Writer.Write(server.NewSuccessResult("Login success")) return } } else { - w.WriteHeader(http.StatusForbidden) + // 非管理员账号返回禁止访问响应 + c.Writer.WriteHeader(http.StatusForbidden) resp := server.NewErrorResult(errors.New("not allowed user/password")) - w.Write(resp) + c.Writer.Write(resp) return } - w.WriteHeader(http.StatusUnauthorized) - w.Write(server.NewErrorResult(errors.New("not allowed user/password"))) + // 默认返回未授权响应 + c.Writer.WriteHeader(http.StatusUnauthorized) + c.Writer.Write(server.NewErrorResult(errors.New("not allowed user/password"))) } // 实现非对称加密 @@ -106,3 +126,66 @@ func GenerateToken(username string) (string, error) { token := jwt.NewWithClaims(jwt.SigningMethodHS256, claim) return token.SignedString([]byte(secret)) } + +func ginBashiAuth(c *gin.Context) { + // first get Url + url := c.Request.URL.Path + // check if url is login + if strings.Contains(url, "login") || strings.Contains(url, "logout") { + c.Next() + return + } + accountMap := map[string]string{} + accountMap[model.GetConfig().Admin.Username] = model.GetConfig().Admin.Password + handler := gin.BasicAuth(accountMap) // 使用gin的BasicAuth中间件进行认证 + handler(c) // 调用认证处理函数 +} + +func jwtAuth(c *gin.Context) { + + config := model.GetConfig().Admin + if config == nil || config.Jwt == nil { + c.AbortWithError(http.StatusInternalServerError, errors.New("Jwt config error")) + // http.Error(w, "Jwt config error", http.StatusInternalServerError) + return + } + url := c.Request.URL.Path + // check if url is login + if strings.Contains(url, "login") || strings.Contains(url, "logout") { + c.Next() + return + } + jwtConfig := config.Jwt + if jwtConfig.Secret == "" { + c.Next() + return + } + // 从cookie中获取token + tokenCookie, err := c.Cookie("auth_token") //r.Cookie("auth_token") + if err != nil { + c.AbortWithStatus(http.StatusUnauthorized) + return + } + tokenString := tokenCookie + token, err := jwt.ParseWithClaims(tokenString, &jwt.RegisteredClaims{}, func(token *jwt.Token) (interface{}, error) { + // 确保签名方法是正确的 + if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) + } + return []byte(jwtConfig.Secret), nil + }) + if err != nil { + // l.Error("Failed to parse JWT: %v", err) + c.AbortWithStatus(http.StatusUnauthorized) + return + } + if claims, ok := token.Claims.(*jwt.RegisteredClaims); ok && token.Valid { + // 验证通过,将用户信息存储在请求上下文中 + // ctx := context.WithValue(r.Context(), "user", claims) + // next.ServeHTTP(w, r.WithContext(ctx)) + c.Set("user", claims) + return + } + c.AbortWithStatus(http.StatusUnauthorized) + // http.Error(w, "Unauthorized.", http.StatusUnauthorized) +} diff --git a/go.mod b/go.mod index 57454e3..aad8178 100644 --- a/go.mod +++ b/go.mod @@ -16,24 +16,35 @@ require ( ) require ( - github.com/gin-contrib/sse v0.1.0 // indirect - github.com/gin-gonic/gin v1.7.4 // indirect - github.com/go-playground/locales v0.14.0 // indirect - github.com/go-playground/universal-translator v0.18.0 // indirect - github.com/go-playground/validator/v10 v10.9.0 // indirect + github.com/bytedance/sonic v1.13.3 // indirect + github.com/bytedance/sonic/loader v0.2.4 // indirect + github.com/cloudwego/base64x v0.1.5 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.9 // indirect + github.com/gin-contrib/sse v1.1.0 // indirect + github.com/gin-gonic/gin v1.10.1 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.26.0 // indirect + github.com/goccy/go-json v0.10.5 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.13.6 // indirect - github.com/leodido/go-urn v1.2.1 // indirect - github.com/mattn/go-isatty v0.0.14 // indirect + github.com/klauspost/cpuid/v2 v2.2.10 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/signalsciences/ac v1.2.0 // indirect - github.com/ugorji/go/codec v1.2.6 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.14 // indirect + golang.org/x/arch v0.18.0 // indirect golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect - golang.org/x/net v0.40.0 // indirect + golang.org/x/net v0.41.0 // indirect golang.org/x/sys v0.33.0 // indirect golang.org/x/text v0.26.0 // indirect - google.golang.org/protobuf v1.27.1 // indirect + google.golang.org/protobuf v1.36.6 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index ba08eea..726c7c9 100644 --- a/go.sum +++ b/go.sum @@ -4,25 +4,48 @@ git.pyer.club/kingecg/godaemon v0.0.0-20231210104221-3a72649c6511 h1:qgNgm8ewkZd git.pyer.club/kingecg/godaemon v0.0.0-20231210104221-3a72649c6511/go.mod h1:6cL7tPbT1m6EaTvrbDg/YhoZG0Mms8WBD10yRGhng4o= git.pyer.club/kingecg/gologger v1.0.1 h1:snCb0ePlfDUglX+CHwNzq5MRK5uNTnPUks1Dnapl/p8= git.pyer.club/kingecg/gologger v1.0.1/go.mod h1:SNSl2jRHPzIpHSzdKOoVG798rtYMjPDPFyxUrEgivkY= +github.com/bytedance/sonic v1.13.3 h1:MS8gmaH16Gtirygw7jV91pDCN33NyMrPbN7qiYhEsF0= +github.com/bytedance/sonic v1.13.3/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY= +github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= +github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4= +github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY= +github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= +github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= github.com/gin-gonic/gin v1.7.4 h1:QmUZXrvJ9qZ3GfWvQ+2wnW/1ePrTEJqPKMYEU3lD/DM= github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= +github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ= +github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-playground/validator/v10 v10.9.0 h1:NgTtmN58D0m8+UuxtYmGztBJB7VnPgjj221I1QHci2A= github.com/go-playground/validator/v10 v10.9.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= +github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= +github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= +github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= +github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= @@ -37,6 +60,10 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= @@ -48,9 +75,13 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -59,6 +90,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/nanmu42/gzip v1.2.0 h1:pZoKNTlnJQJ4xM5Zi/EuIch77/x/9ww9PLsA3zEHLlU= github.com/nanmu42/gzip v1.2.0/go.mod h1:ubXkuAEakeUraJOokoM5/XuDdcjotF4Q+TvFSCgPSEg= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -70,16 +103,27 @@ github.com/samber/lo v1.39.0/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXn github.com/signalsciences/ac v1.2.0 h1:6UcueKRSJn7iHhq1vKU7R0EVhzCJf77tD6HjAGcGDSs= github.com/signalsciences/ac v1.2.0/go.mod h1:jnlGjtNM8dyGcnOdZjY35vHmUtOn5M5K4U+BzcVPjN0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ= github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw= +github.com/ugorji/go/codec v1.2.14 h1:yOQvXCBc3Ij46LRkRoh4Yd5qK6LVOgi0bYOXfb7ifjw= +github.com/ugorji/go/codec v1.2.14/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +golang.org/x/arch v0.18.0 h1:WN9poc33zL4AzGxqf8VtpKUnGvMi8O9lhNyBMF/85qc= +golang.org/x/arch v0.18.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= @@ -93,6 +137,8 @@ golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -102,6 +148,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -120,6 +167,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= @@ -132,3 +181,7 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/server/middleware.go b/server/middleware.go index d583f6d..5a0eca8 100644 --- a/server/middleware.go +++ b/server/middleware.go @@ -12,6 +12,7 @@ import ( "git.pyer.club/kingecg/gohttpd/model" "git.pyer.club/kingecg/gologger" + "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt/v5" ) @@ -88,14 +89,14 @@ func NewMiddlewareLink() *MiddlewareLink { } func BasicAuth(w http.ResponseWriter, r *http.Request, next http.Handler) { - config := model.GetConfig() + config := getServerConfig(r) - if config.Admin.Username == "" || config.Admin.Password == "" { + if config.Username == "" || config.Password == "" { next.ServeHTTP(w, r) return } user, pass, ok := r.BasicAuth() - if ok && user == config.Admin.Username && pass == config.Admin.Password { + if ok && user == config.Username && pass == config.Password { next.ServeHTTP(w, r) } else { w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`) @@ -232,3 +233,19 @@ func IPAccessControl(w http.ResponseWriter, r *http.Request, next http.Handler) func Done(w http.ResponseWriter, r *http.Request, next http.Handler) { next.ServeHTTP(w, r) } + +// GinJwtAuth 返回Gin框架兼容的JWT认证中间件 +func GinJwtAuth() gin.HandlerFunc { + return func(c *gin.Context) { + // 实现JWT认证逻辑 + c.Next() + } +} + +// GinBasicAuth 返回Gin框架兼容的基础认证中间件 +func GinBasicAuth() gin.HandlerFunc { + return func(c *gin.Context) { + // 实现基础认证逻辑 + c.Next() + } +}