127 lines
2.9 KiB
Go
127 lines
2.9 KiB
Go
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")
|
|
}
|