diff --git a/cmd/picgo.go b/cmd/picgo.go index b813e1a..d71bc5b 100644 --- a/cmd/picgo.go +++ b/cmd/picgo.go @@ -42,10 +42,10 @@ var picgoCmd = &cobra.Command{ Use: "picgo", Run: func(cmd *cobra.Command, args []string) { // 创建路由 - r := router.InitRouter() + router.InitRouter() // 启动HTTP服务器 log.Println("Serving on http://localhost:8082") - err := http.ListenAndServe(":8082", r) + err := http.ListenAndServe(":8082", nil) if err != nil { log.Fatalf("Failed to start server: %v", err) } diff --git a/corelib/captcha/captcha.go b/corelib/captcha/captcha.go index 2632f19..1ba269d 100644 --- a/corelib/captcha/captcha.go +++ b/corelib/captcha/captcha.go @@ -61,7 +61,7 @@ func Verify(id string, code string) (ok bool) { return } // redis存储验证码和用户输入验证码对比 - if strings.ToLower(redisCode) == code { + if strings.ToLower(redisCode) == strings.ToLower(code) { return true } return diff --git a/corelib/captcha/store.go b/corelib/captcha/store.go index 2aa1736..a292292 100644 --- a/corelib/captcha/store.go +++ b/corelib/captcha/store.go @@ -42,5 +42,5 @@ func GetCode(cid string) (code string, err error) { // captcha缓存key拼接 func genRedisKey(id string) (res string) { - return corelib.AdminCaptchaKey + id + return corelib.CaptchaKey + id } diff --git a/corelib/json.go b/corelib/json.go new file mode 100644 index 0000000..653d951 --- /dev/null +++ b/corelib/json.go @@ -0,0 +1,13 @@ +package corelib + +import "encoding/json" + +// JsonMarshal JSON封装 +func JsonMarshal(src interface{}) (res []byte, err error) { + return json.Marshal(src) +} + +// JsonUnmarshal JSON解封 +func JsonUnmarshal(data []byte, res interface{}) (err error) { + return json.Unmarshal(data, res) +} diff --git a/corelib/redis.go b/corelib/redis.go index 65d7963..f8452bd 100644 --- a/corelib/redis.go +++ b/corelib/redis.go @@ -8,8 +8,9 @@ import ( ) var ( - RdbClient *redis.Client - AdminCaptchaKey = "admin:captcha:" // 验证码存储key + RdbClient *redis.Client + CaptchaKey = "picgo:captcha:" // 验证码存储key + UserKey = "picgo:user:" ) func NewRedis() { diff --git a/corelib/response.go b/corelib/response.go index 85f6aa9..d89d5d5 100644 --- a/corelib/response.go +++ b/corelib/response.go @@ -15,7 +15,7 @@ type JsonResponse struct { // WriteJsonResponse 用于写入JSON响应 func WriteJsonResponse(w http.ResponseWriter, status int, message string, data any) { w.Header().Set("Content-Type", "application/json") - w.WriteHeader(status) + w.WriteHeader(http.StatusOK) response := JsonResponse{ Status: status, Message: message, diff --git a/corelib/session.go b/corelib/session.go index 46e820b..3217de6 100644 --- a/corelib/session.go +++ b/corelib/session.go @@ -1,7 +1,7 @@ package corelib import ( - "gopkg.in/boj/redistore.v1" + "github.com/boj/redistore" "picgo/configs" ) @@ -9,10 +9,10 @@ var SessionStore *redistore.RediStore func NewSessionStore() { // Fetch new store. - store, err := redistore.NewRediStore(10, "tcp", configs.Settings.Redis.Addr, configs.Settings.Redis.Password) + store, err := redistore.NewRediStore(10, "tcp", configs.Settings.Redis.Addr, configs.Settings.Redis.Password, []byte(configs.Settings.SessionsKey)) if err != nil { panic(err) } SessionStore = store - defer store.Close() + //defer store.Close() } diff --git a/corelib/template.go b/corelib/template.go index c8cc54a..5f5f260 100644 --- a/corelib/template.go +++ b/corelib/template.go @@ -5,7 +5,7 @@ import ( "net/http" ) -func TemplateHandler(w http.ResponseWriter, r *http.Request, data any, filenames ...string) { +func TemplateHandler(w http.ResponseWriter, data any, filenames ...string) { // 解析模板文件 tmpl, err := template.ParseFiles(filenames...) if err != nil { diff --git a/data/user.go b/data/user.go new file mode 100644 index 0000000..527eb6c --- /dev/null +++ b/data/user.go @@ -0,0 +1,62 @@ +package data + +import ( + "context" + "picgo/corelib" + "picgo/model" + "time" +) + +// SysUserSelectByUsername 通过用户名查询用户 +func SysUserSelectByUsername(userName string) (model.SysUser, error) { + var ( + err error + user model.SysUser + ) + if user, err = SysUserGetCacheByUsername(userName); err == nil { + corelib.Logger.Infoln("SysUserSelectByUsername 从缓存获取用户信息成功: ", user.Username) + return user, nil + } else { + corelib.Logger.Infoln("SysUserSelectByUsername 从缓存获取用户信息失败: ", err) + } + if err = corelib.DbMysql.Model(model.SysUser{Username: userName}).First(&user).Error; err != nil { + corelib.Logger.Infoln("SysUserSelectByUsername 数据库中查询用户信息失败: ", err) + return user, err + } + if err = SysUserSetCacheByUsername(user); err != nil { + corelib.Logger.Infoln("SysUserSelectByUsername 缓存用户信息失败: ", err) + return user, nil + } + return user, nil +} + +func SysUserSetCacheByUsername(user model.SysUser) error { + var ( + jsonData []byte + err error + ) + if jsonData, err = corelib.JsonMarshal(user); err != nil { + return err + } + key := corelib.UserKey + user.Username + if err = corelib.RdbClient.Set(context.Background(), key, string(jsonData), 5*time.Minute).Err(); err != nil { + return err + } + return nil +} + +// SysUserGetCacheByUsername redis获取用户信息 +func SysUserGetCacheByUsername(userName string) (model.SysUser, error) { + var ( + err error + user model.SysUser + userCache string + ) + if userCache, err = corelib.RdbClient.Get(context.Background(), corelib.UserKey+userName).Result(); err != nil { + return model.SysUser{}, err + } + if err = corelib.JsonUnmarshal([]byte(userCache), &user); err != nil { + return model.SysUser{}, err + } + return user, nil +} diff --git a/deploy/picgo-dev.yml b/deploy/picgo-dev.yml index 13765cb..4152c34 100644 --- a/deploy/picgo-dev.yml +++ b/deploy/picgo-dev.yml @@ -6,12 +6,12 @@ server: port: 8181 host: localhost node_id: 1 - log_path: tmp/admin-server.log + log_path: tmp/picgo.log environment: dev static_path: static upload_path: static/pic upload_max_size: 3 - sessions_key: eyjhbgcioijiuzi1niisinr5cci6ikpx + sessions_key: afE+7AztxjvTc5MmQ/8RuQw1aabgOLMlAKGMKLseRkc= session_name: picgo # redis redis: diff --git a/go.mod b/go.mod index d5b0139..e170bff 100644 --- a/go.mod +++ b/go.mod @@ -3,14 +3,18 @@ module picgo go 1.22 require ( + github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff github.com/bwmarrin/snowflake v0.3.0 github.com/dlclark/regexp2 v1.11.2 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 + github.com/gorilla/csrf v1.7.2 + github.com/gorilla/mux v1.8.1 github.com/llgcode/draw2d v0.0.0-20240627062922-0ed1ff131195 github.com/redis/go-redis/v9 v9.5.4 github.com/spf13/cobra v1.8.1 go.uber.org/zap v1.27.0 golang.org/x/crypto v0.25.0 + gopkg.in/boj/redistore.v1 v1.0.0-20160128113310-fc113767cd6b gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/yaml.v3 v3.0.1 gorm.io/driver/mysql v1.5.7 @@ -22,7 +26,7 @@ require ( github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/garyburd/redigo v1.6.4 // indirect github.com/go-sql-driver/mysql v1.7.0 // indirect - github.com/gorilla/csrf v1.7.2 // indirect + github.com/gomodule/redigo v2.0.0+incompatible // indirect github.com/gorilla/securecookie v1.1.2 // indirect github.com/gorilla/sessions v1.3.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect @@ -32,5 +36,4 @@ require ( go.uber.org/multierr v1.10.0 // indirect golang.org/x/image v0.18.0 // indirect golang.org/x/text v0.16.0 // indirect - gopkg.in/boj/redistore.v1 v1.0.0-20160128113310-fc113767cd6b // indirect ) diff --git a/go.sum b/go.sum index 3461472..e3b92b3 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff h1:RmdPFa+slIr4SCBg4st/l/vZWVe9QJKMXGO60Bxbe04= +github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P97fT2CiHkbFQwkK3mjsFAP6zCYV2aXtjw= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= @@ -19,10 +21,19 @@ github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0= +github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/csrf v1.7.2 h1:oTUjx0vyf2T+wkrx09Trsev1TE+/EbDAeHtSTbtC2eI= github.com/gorilla/csrf v1.7.2/go.mod h1:F1Fj3KG23WYHE6gozCmBAezKookxbIvUJT+121wTuLk= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= +github.com/gorilla/sessions v1.1.1/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= github.com/gorilla/sessions v1.3.0 h1:XYlkq7KcpOB2ZhHBPv5WpjMIxrQosiZanfoy1HLZFzg= github.com/gorilla/sessions v1.3.0/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= diff --git a/handler/captcha.go b/handler/captcha.go index e6fa48a..e3258e3 100644 --- a/handler/captcha.go +++ b/handler/captcha.go @@ -17,6 +17,7 @@ func CaptchaHandler(w http.ResponseWriter, r *http.Request) { err error ) captchaId := getCaptchaId(r) + corelib.Logger.Info("captchaHandler cid: ", captchaId) if res, err = generateCaptcha(captchaId); err != nil { corelib.WriteJsonResponse(w, 1030, "生产验证码失败", nil) return diff --git a/handler/index.go b/handler/index.go index 72636d2..029daee 100644 --- a/handler/index.go +++ b/handler/index.go @@ -11,9 +11,9 @@ func IndexHandler(w http.ResponseWriter, r *http.Request) { Title string Active string }{ - Title: "Admin Dashboard", + Title: "Dashboard", Active: r.URL.Path, } - corelib.TemplateHandler(w, r, data, "view/layout.html", "view/index.html") + corelib.TemplateHandler(w, data, "view/layout.html", "view/index.html") } } diff --git a/handler/login.go b/handler/login.go index 9fc4192..15e917c 100644 --- a/handler/login.go +++ b/handler/login.go @@ -2,18 +2,35 @@ package handler import ( "encoding/json" + "github.com/gorilla/csrf" "net/http" "picgo/configs" "picgo/corelib" "picgo/corelib/captcha" + "picgo/data" "picgo/model" ) func LoginHandler(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: - - corelib.TemplateHandler(w, r, nil, "view/login.html") + data := map[string]interface{}{ + csrf.TemplateTag: csrf.TemplateField(r), + } + //data := map[string]interface{}{csrf.TemplateTag: csrf.TemplateField(r)} + corelib.Logger.Info("data: ", data, data["csrfToken"]) + corelib.TemplateHandler(w, data, "view/login.html") + //tmpl, err := template.ParseFiles("view/login.html") + //if err != nil { + // http.Error(w, "Internal Server Error", http.StatusInternalServerError) + // return + //} + //if err = tmpl.Execute(w, map[string]interface{}{ + // csrf.TemplateTag: csrf.TemplateField(r), + //}); err != nil { + // http.Error(w, "Internal Server Error", http.StatusInternalServerError) + // return + //} case http.MethodPost: loginService(w, r) default: @@ -33,11 +50,13 @@ func loginService(w http.ResponseWriter, r *http.Request) { return } cid := getCaptchaId(r) + corelib.Logger.Info("LoginRequest: ", res) + corelib.Logger.Info("login cid: ", cid) if ok := captcha.Verify(cid, res.Captcha); !ok { corelib.WriteJsonResponse(w, 1040, "验证码错误", nil) return } - if user, err = sysUserSelectDataByUsername(res.Username); err != nil { + if user, err = data.SysUserSelectByUsername(res.Username); err != nil { corelib.WriteJsonResponse(w, 1041, "用户不存在", nil) return } @@ -49,18 +68,19 @@ func loginService(w http.ResponseWriter, r *http.Request) { session, _ := corelib.SessionStore.Get(r, configs.Settings.Server.SessionName) session.Values["username"] = user.Username if err = session.Save(r, w); err != nil { - corelib.WriteJsonResponse(w, 1043, "回话保存失败", nil) + corelib.Logger.Infoln("session save err:", err) + corelib.WriteJsonResponse(w, 1043, "会话保存失败", nil) return } w.Header().Set("Content-Type", "application/json") corelib.WriteJsonResponse(w, 200, "登录成功", nil) } -// sysUserSelectDataByUsername 通过用户名查询用户 -func sysUserSelectDataByUsername(userName string) (model.SysUser, error) { - var user model.SysUser - if err := corelib.DbMysql.Model(model.SysUser{Username: userName}).First(&user).Error; err != nil { - return user, err - } - return user, nil -} +//// sysUserSelectDataByUsername 通过用户名查询用户 +//func sysUserSelectDataByUsername(userName string) (model.SysUser, error) { +// var user model.SysUser +// if err := corelib.DbMysql.Model(model.SysUser{Username: userName}).First(&user).Error; err != nil { +// return user, err +// } +// return user, nil +//} diff --git a/handler/profile.go b/handler/profile.go index 71e316d..5a287fb 100644 --- a/handler/profile.go +++ b/handler/profile.go @@ -14,6 +14,6 @@ func ProfileHandler(w http.ResponseWriter, r *http.Request) { Title: "Admin Dashboard", Active: r.URL.Path, } - corelib.TemplateHandler(w, r, data, "view/layout.html", "view/profile.html") + corelib.TemplateHandler(w, data, "view/layout.html", "view/profile.html") } } diff --git a/handler/settings.go b/handler/settings.go index ef339af..133004d 100644 --- a/handler/settings.go +++ b/handler/settings.go @@ -14,6 +14,6 @@ func SettingsHandler(w http.ResponseWriter, r *http.Request) { Title: "Admin Dashboard", Active: r.URL.Path, } - corelib.TemplateHandler(w, r, data, "view/layout.html", "view/settings.html") + corelib.TemplateHandler(w, data, "view/layout.html", "view/settings.html") } } diff --git a/handler/static.go b/handler/static.go index 3ce6195..e5829fb 100644 --- a/handler/static.go +++ b/handler/static.go @@ -4,31 +4,22 @@ import ( "net/http" "os" "path/filepath" + "picgo/configs" ) -func StaticHandler(w http.ResponseWriter, r *http.Request) { +func StaticHandler() http.Handler { // 文件服务器的根目录 - root := "./static" - - // 自定义文件处理器 - fileHandler := http.StripPrefix("/static/", http.FileServer(http.Dir(root))) - - // 获取请求的路径 - path := filepath.Join(root, r.URL.Path[len("/static/"):]) - - // 检查路径是否是一个目录 - info, err := os.Stat(path) - if err != nil { - // 如果文件不存在,返回404 - http.NotFound(w, r) - return - } - if info.IsDir() { - // 如果是目录,返回404 - http.NotFound(w, r) - return - } - - // 处理文件 - fileHandler.ServeHTTP(w, r) + root := configs.Settings.Server.StaticPath + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // 获取文件路径 + path := filepath.Join(root, r.URL.Path) + // 检查路径是否为目录 + info, err := os.Stat(path) + if err == nil && info.IsDir() { + http.NotFound(w, r) // 如果是目录,则返回404 + return + } + // 否则提供文件 + http.ServeFile(w, r, path) + }) } diff --git a/middleware/auth.go b/middleware/auth.go index b25be6c..41e7290 100644 --- a/middleware/auth.go +++ b/middleware/auth.go @@ -1,23 +1,35 @@ package middleware import ( - "log" "net/http" - "time" + "picgo/configs" + "picgo/corelib" + "picgo/data" + "strings" ) // LoginMiddleware 登录 // 添加日志中间件到路由器 使用:r.Handle("/", LoginMiddleware(http.HandlerFunc(handler))) func LoginMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // 记录请求时间和路径 - start := time.Now() - log.Printf("Started %s %s", r.Method, r.URL.Path) + resPath := r.URL.Path + if resPath == "/login" || resPath == "/captcha" || strings.HasPrefix(resPath, "/static") { + next.ServeHTTP(w, r) + } + session, _ := corelib.SessionStore.Get(r, configs.Settings.Server.SessionName) + username, ok := session.Values["username"].(string) + if !ok || username == "" { + http.Redirect(w, r, "/login", http.StatusFound) + return + } + var ( + //user model.SysUser + err error + ) + if _, err = data.SysUserSelectByUsername(username); err != nil { + http.Redirect(w, r, "/login", http.StatusFound) + return + } - // 调用下一个处理程序 next.ServeHTTP(w, r) - - // 记录请求处理时间 - duration := time.Since(start) - log.Printf("Completed %s %s in %v", r.Method, r.URL.Path, duration) }) } diff --git a/middleware/cors.go b/middleware/cors.go new file mode 100644 index 0000000..f309182 --- /dev/null +++ b/middleware/cors.go @@ -0,0 +1,21 @@ +package middleware + +import "net/http" + +// CorsMiddleware 是处理跨域请求的中间件 +func CorsMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") + w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization, X-CSRF-Token") + w.Header().Set("Access-Control-Expose-Headers", "Content-Length, X-CSRF-Token") + + // 处理预检请求 + if r.Method == http.MethodOptions { + w.WriteHeader(http.StatusOK) + return + } + + next.ServeHTTP(w, r) + }) +} diff --git a/router/router.go b/router/router.go index 0a23745..bd9c819 100644 --- a/router/router.go +++ b/router/router.go @@ -1,20 +1,42 @@ package router import ( + "github.com/gorilla/csrf" + "github.com/gorilla/mux" "net/http" + "picgo/configs" "picgo/handler" + "picgo/middleware" ) -func InitRouter() *http.ServeMux { - var mux *http.ServeMux +func InitRouter() *mux.Router { + var secure bool + if configs.Settings.Server.Environment == "dev" { + secure = false + } else { + secure = true + } + // 设置CSRF保护 + CSRF := csrf.Protect( + []byte(configs.Settings.Server.SessionsKey), + csrf.Secure(secure), // 在开发环境中禁用HTTPS + csrf.RequestHeader("X-CSRF-Token"), + ) // 创建新的路由器 - mux = http.NewServeMux() - mux.HandleFunc("/", handler.IndexHandler) - mux.HandleFunc("/settings", handler.SettingsHandler) - mux.HandleFunc("/profile", handler.ProfileHandler) - mux.HandleFunc("/static/", handler.StaticHandler) - mux.HandleFunc("/login", handler.LoginHandler) - mux.HandleFunc("/api/v1/upload", handler.UploadFileHandler) - mux.HandleFunc("/captcha", handler.CaptchaHandler) - return mux + r := mux.NewRouter() + // 处理静态文件 + //staticDir := "static" + r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", handler.StaticHandler())) + r.HandleFunc("/login", handler.LoginHandler) + r.HandleFunc("/captcha", handler.CaptchaHandler) + + r.HandleFunc("/settings", handler.SettingsHandler) + r.HandleFunc("/profile", handler.ProfileHandler) + r.HandleFunc("/api/v1/upload", handler.UploadFileHandler) + // 路由鉴权 + r.Handle("/", middleware.LoginMiddleware(http.HandlerFunc(handler.IndexHandler))).Methods(http.MethodGet) + // 应用 CORS 中间件 + http.Handle("/", middleware.CorsMiddleware(CSRF(r))) + + return r } diff --git a/static/img/add.svg b/static/img/add.svg new file mode 100644 index 0000000..4826b3a --- /dev/null +++ b/static/img/add.svg @@ -0,0 +1,22 @@ + + \ No newline at end of file diff --git a/static/js/common.js b/static/js/common.js new file mode 100644 index 0000000..e2c546d --- /dev/null +++ b/static/js/common.js @@ -0,0 +1,54 @@ +function Common() { + +} + +// 错误弹窗 +Common.prototype.AlertError = function (msg) { + swal('提示', msg, 'error'); +} + +// 弹窗 +Common.prototype.AlertToast = function (msg, type) { + swal({ + 'title': msg, + 'text': '', + 'type': type, + 'showCancelButton': false, + 'showConfirmButton': false, + 'timer': 1000 + }) +} + +// 带确认按钮的弹窗 +Common.prototype.AlertConfirm = function (params) { + swal({ + 'title': params['title'] ? params['title'] : '提示', + 'showCancelButton': true, + 'showConfirmButton': true, + 'type': params['type'] ? params['type'] : '', + 'confirmButtonText': params['confirmText'] ? params['confirmText'] : '确定', + 'cancelButtonText': params['cancelText'] ? params['cancelText'] : '取消', + 'text': params['text'] ? params['text'] : '' + }, function (isConfirm) { + if (isConfirm) { + if (params['confirmCallback']) { + params['confirmCallback']() + } + } else { + if (params['cancelCallback']) { + params['cancelCallback']() + } + } + }) +} + +// 成功弹窗 +Common.prototype.AlertSuccessToast = function (msg) { + if (!msg) { + msg = '成功!' + } + this.AlertToast(msg, 'success') +} + +var Alert = new Common() + diff --git a/static/js/login.js b/static/js/login.js index a1f3974..0203559 100644 --- a/static/js/login.js +++ b/static/js/login.js @@ -13,10 +13,48 @@ Login.prototype.RefreshCaptcha = function () { $("#captcha-img").attr('src', self.captchaUrl); //显示图片 }) } +// +Login.prototype.LoginClick = function () { + let self = this; + let csrfToken = document.getElementsByName("gorilla.csrf.Token")[0].value + $("#login-btn").click(function () { + // 获取参数 + let username = $("#login-username").val() + let password = $("#login-password").val() + let captcha = $("#login-captcha").val() + + $.ajax({ + url: '/login', + method: 'POST', + data: JSON.stringify({ + username: username, + password: password, + captcha: captcha + }), + headers: { + 'Content-Type': 'application/json', + "X-CSRF-Token": csrfToken + }, + success: function (result) { + if (result["status"] === 200) { + Alert.AlertSuccessToast(result["message"]) + window.location.href = "/" + } else { + Alert.AlertError(result["message"]) + } + }, + error: function (xhr, status, error) { + Alert.AlertError("服务器内部错误") + console.log('请求失败:', error); + } + }); + }) +} Login.prototype.run = function () { this.RefreshCaptcha() + this.LoginClick() } // 构造执行入口 diff --git a/view/index.html b/view/index.html index aad3071..30be434 100644 --- a/view/index.html +++ b/view/index.html @@ -1,4 +1,23 @@ {{define "content"}} -
Welcome to the Admin Panel.
+拖拽文件到此区域或 + 点此上传 +
+支持上传照片、视频、ZIP、pdf等多种文件,最大支持100M,上传后支持复制url、base64、Markdown 照片三种方式
+