package api import ( "caddydash/config" "caddydash/db" "caddydash/user" "net/http" "strings" "github.com/fenthope/sessions" "github.com/infinite-iroha/touka" ) var ( exactMatchPaths = map[string]struct{}{ "/login": {}, "/login.html": {}, "/v0/api/auth/login": {}, "/v0/api/auth/init": {}, "/init.html": {}, "/favicon.ico": {}, } prefixMatchPaths = []string{ // 保持前缀匹配,因为数量少 "/js/", "/css/", } loginMatchPaths = map[string]struct{}{ "/login": {}, "/login.html": {}, "/v0/api/auth/login": {}, } initMatchPaths = map[string]struct{}{ "/v0/api/auth/init": {}, "/init.html": {}, } ) func isPassPath(requestPath string) bool { // 精确匹配 if _, ok := exactMatchPaths[requestPath]; ok { return true } // 前缀匹配 for _, prefix := range prefixMatchPaths { if strings.HasPrefix(requestPath, prefix) { return true } } return false } func isLoginPath(requestPath string) bool { if _, ok := loginMatchPaths[requestPath]; ok { return true } return false } func isInitPath(requestPath string) bool { if _, ok := initMatchPaths[requestPath]; ok { return true } return false } func SessionMiddleware(cdb *db.ConfigDB) touka.HandlerFunc { return func(c *touka.Context) { session := sessions.Default(c) requestPath := c.Request.URL.Path pass := isPassPath(requestPath) if !user.IsAdminInit() && !pass || !user.IsAdminInit() && isLoginPath(requestPath) { c.Redirect(http.StatusFound, "/init.html") c.Abort() return } else if user.IsAdminInit() && isInitPath(requestPath) { c.Redirect(http.StatusFound, "/login.html") c.Abort() return } if session.Get("authenticated") != true && !pass { c.Redirect(http.StatusFound, "/login.html") c.Abort() return } c.Next() } } func AuthLogin(c *touka.Context, cfg *config.Config, cdb *db.ConfigDB) { username := c.PostForm("username") password := c.PostForm("password") // 输入验证 if username == "" || password == "" { c.Errorf("Username or password not provided") c.JSON(http.StatusBadRequest, touka.H{"error": "Need username and password"}) return } // 验证账户密码 pass, err := user.CheckLogin(username, password, cdb) if err != nil { c.Errorf("Failed to check login: %v", err) c.JSON(http.StatusInternalServerError, touka.H{"error": "Internal Auth Check Error"}) return } if !pass { c.Errorf("Invalid username or password") c.JSON(http.StatusUnauthorized, touka.H{"error": "Invalid username or password"}) return } session := sessions.Default(c) session.Set("authenticated", true) session.Save() c.Infof("Login successful for user: %s", username) c.JSON(http.StatusOK, touka.H{"success": true}) } func AuthLogout(c *touka.Context) { session := sessions.Default(c) session.Clear() session.Set("authenticated", false) session.Save() c.Redirect(http.StatusFound, "/login.html") }