refactor(auth): delegate access control to be-system

Remove Agent Desk users, roles, login sessions, tokens, and local permission persistence. Expose the backend as an embeddable ai-agent module with host-provided subject lookup and operation authorization callbacks, and complete the frontend/backend repository split.
This commit is contained in:
t
2026-08-21 00:41:07 +08:00
parent 3d47227fbd
commit 2bbf42b741
447 changed files with 1901 additions and 8920 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"io"
"os"
"agent-desk/internal/pkg/config"
"code.tczkiot.com/wlw/ai-agent/internal/pkg/config"
)
func printBanner() {
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"strings"
"testing"
"agent-desk/internal/pkg/config"
"code.tczkiot.com/wlw/ai-agent/internal/pkg/config"
)
func TestRenderBanner(t *testing.T) {
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"strings"
"time"
"agent-desk/internal/pkg/config"
"code.tczkiot.com/wlw/ai-agent/internal/pkg/config"
"github.com/mlogclub/simple/sqls"
"gorm.io/driver/mysql"
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"path/filepath"
"testing"
"agent-desk/internal/pkg/config"
"code.tczkiot.com/wlw/ai-agent/internal/pkg/config"
)
func TestNewDialector(t *testing.T) {
+7 -13
View File
@@ -1,17 +1,15 @@
package bootstrap
import (
"agent-desk/internal/ai/rag/vectordb"
"agent-desk/internal/oidcclient"
"agent-desk/internal/pkg/config"
"agent-desk/internal/pkg/i18nx"
"agent-desk/internal/pkg/logx"
"agent-desk/internal/services/cronx"
"agent-desk/internal/wxwork"
"context"
"code.tczkiot.com/wlw/ai-agent/internal/ai/rag/vectordb"
"code.tczkiot.com/wlw/ai-agent/internal/pkg/config"
"code.tczkiot.com/wlw/ai-agent/internal/pkg/i18nx"
"code.tczkiot.com/wlw/ai-agent/internal/pkg/logx"
"code.tczkiot.com/wlw/ai-agent/internal/services/cronx"
"code.tczkiot.com/wlw/ai-agent/internal/wxwork"
"log/slog"
_ "agent-desk/internal/services/event_handlers"
_ "code.tczkiot.com/wlw/ai-agent/internal/services/event_handlers"
)
func Init(configPath string) error {
@@ -46,9 +44,5 @@ func Init(configPath string) error {
cronx.Init()
wxwork.Init()
if err := oidcclient.Init(context.Background()); err != nil {
slog.Error("init oidc failed", "error", err)
return err
}
return nil
}
+2 -2
View File
@@ -1,8 +1,8 @@
package bootstrap
import (
"agent-desk/internal/migration"
"agent-desk/internal/models"
"code.tczkiot.com/wlw/ai-agent/internal/migration"
"code.tczkiot.com/wlw/ai-agent/internal/models"
"github.com/mlogclub/simple/sqls"
)
+4 -58
View File
@@ -1,34 +1,17 @@
package bootstrap
import (
"agent-desk/internal/handlers/api"
"agent-desk/internal/handlers/dashboard"
"agent-desk/internal/handlers/third"
"code.tczkiot.com/wlw/ai-agent/internal/handlers/api"
"code.tczkiot.com/wlw/ai-agent/internal/handlers/dashboard"
"code.tczkiot.com/wlw/ai-agent/internal/handlers/third"
"github.com/gin-gonic/gin"
)
func registerApiAuthRoutes(group *gin.RouterGroup) {
group.POST("/login", api.Login)
group.POST("/logout", api.Logout)
group.GET("/profile", api.Profile)
group.GET("/wxwork_callback", api.WxWorkCallback)
group.POST("/wxwork_exchange", api.WxWorkExchange)
group.GET("/wxwork_login", api.WxWorkLogin)
group.GET("/wxwork_qr_login", api.WxWorkQRLogin)
group.GET("/oidc_callback", api.OIDCCallback)
group.POST("/oidc_exchange", api.OIDCExchange)
group.GET("/oidc_login", api.OIDCLogin)
}
func registerApiChannelRoutes(group *gin.RouterGroup) {
group.Any("/config", api.ChannelAnyConfig)
}
func registerApiCustomerRoutes(group *gin.RouterGroup) {
group.POST("/session_exchange", api.CustomerPostSession_exchange)
}
func registerApiConversationRoutes(group *gin.RouterGroup) {
group.GET("/:id", api.ConversationGetBy)
group.POST("/close", api.ConversationPostClose)
@@ -47,19 +30,6 @@ func registerDashboardDashboardRoutes(group *gin.RouterGroup) {
group.GET("/overview", dashboard.DashboardGetOverview)
}
func registerDashboardUserRoutes(group *gin.RouterGroup) {
group.GET("/:id", dashboard.UserGetBy)
group.POST("/assign_role", dashboard.UserPostAssign_role)
group.POST("/change_password", dashboard.UserPostChange_password)
group.POST("/create", dashboard.UserPostCreate)
group.POST("/delete", dashboard.UserPostDelete)
group.Any("/list", dashboard.UserAnyList)
group.Any("/list_all", dashboard.UserAnyList_all)
group.POST("/reset_password", dashboard.UserPostReset_password)
group.POST("/update", dashboard.UserPostUpdate)
group.POST("/update_status", dashboard.UserPostUpdate_status)
}
func registerDashboardCompanyRoutes(group *gin.RouterGroup) {
group.GET("/:id", dashboard.CompanyGetBy)
group.POST("/create", dashboard.CompanyPostCreate)
@@ -86,30 +56,6 @@ func registerDashboardCustomerContactRoutes(group *gin.RouterGroup) {
group.POST("/update", dashboard.CustomerContactPostUpdate)
}
func registerDashboardRoleRoutes(group *gin.RouterGroup) {
group.GET("/:id", dashboard.RoleGetBy)
group.POST("/assign_permission", dashboard.RolePostAssign_permission)
group.POST("/create", dashboard.RolePostCreate)
group.POST("/delete", dashboard.RolePostDelete)
group.Any("/list", dashboard.RoleAnyList)
group.GET("/list_all", dashboard.RoleGetList_all)
group.POST("/update", dashboard.RolePostUpdate)
group.POST("/update_sort", dashboard.RolePostUpdate_sort)
group.POST("/update_status", dashboard.RolePostUpdate_status)
}
func registerDashboardPermissionRoutes(group *gin.RouterGroup) {
group.GET("/:id", dashboard.PermissionGetBy)
group.Any("/list", dashboard.PermissionAnyList)
group.POST("/sync", dashboard.PermissionPostSync)
}
func registerDashboardSessionRoutes(group *gin.RouterGroup) {
group.Any("/list", dashboard.SessionAnyList)
group.POST("/revoke", dashboard.SessionPostRevoke)
group.POST("/revoke/by/user", dashboard.SessionPostRevokeByUser)
}
func registerDashboardTagRoutes(group *gin.RouterGroup) {
group.GET("/:id", dashboard.TagGetBy)
group.POST("/create", dashboard.TagPostCreate)
@@ -178,7 +124,6 @@ func registerDashboardChannelRoutes(group *gin.RouterGroup) {
group.POST("/create", dashboard.ChannelPostCreate)
group.POST("/delete", dashboard.ChannelPostDelete)
group.Any("/list", dashboard.ChannelAnyList)
group.POST("/reset_user_token_secret", dashboard.ChannelPostReset_user_token_secret)
group.POST("/rollback_ai_agent_rollout", dashboard.ChannelPostRollback_ai_agent_rollout)
group.POST("/update", dashboard.ChannelPostUpdate)
group.POST("/update_status", dashboard.ChannelPostUpdate_status)
@@ -194,6 +139,7 @@ func registerDashboardAgentRoutes(group *gin.RouterGroup) {
group.POST("/delete", dashboard.AgentPostDelete)
group.Any("/list", dashboard.AgentAnyList)
group.GET("/list_all", dashboard.AgentGetList_all)
group.GET("/user-options", dashboard.AgentGetUser_options)
group.POST("/update", dashboard.AgentPostUpdate)
}
+13 -19
View File
@@ -6,21 +6,21 @@ import (
"strings"
"time"
"agent-desk/internal/ai/mcps"
_ "agent-desk/internal/ai/runtime"
"agent-desk/internal/handlers/api"
"agent-desk/internal/middleware"
"agent-desk/internal/pkg/config"
"agent-desk/internal/pkg/ginx"
"agent-desk/internal/pkg/httpx"
"agent-desk/internal/pkg/i18nx"
"agent-desk/internal/pkg/tracex"
"agent-desk/internal/services"
"code.tczkiot.com/wlw/ai-agent/internal/ai/mcps"
_ "code.tczkiot.com/wlw/ai-agent/internal/ai/runtime"
"code.tczkiot.com/wlw/ai-agent/internal/handlers/api"
"code.tczkiot.com/wlw/ai-agent/internal/middleware"
"code.tczkiot.com/wlw/ai-agent/internal/pkg/config"
"code.tczkiot.com/wlw/ai-agent/internal/pkg/ginx"
"code.tczkiot.com/wlw/ai-agent/internal/pkg/httpx"
"code.tczkiot.com/wlw/ai-agent/internal/pkg/i18nx"
"code.tczkiot.com/wlw/ai-agent/internal/pkg/tracex"
"code.tczkiot.com/wlw/ai-agent/internal/services"
"github.com/gin-gonic/gin"
"github.com/mlogclub/simple/web"
_ "agent-desk/internal/services/wx_callback_handlers"
_ "code.tczkiot.com/wlw/ai-agent/internal/services/wx_callback_handlers"
)
func NewServer() (*gin.Engine, error) {
@@ -60,8 +60,8 @@ func NewServer() (*gin.Engine, error) {
func corsMiddleware() gin.HandlerFunc {
allowedOrigins := config.Current().Server.CORS.AllowedOrigins
allowHeaders := "Origin, Content-Type, Accept, Authorization, X-Requested-With, X-Guest-Id, X-Channel-Id, X-External-Id, X-External-Name, X-Customer-Session-Token, X-Customer-Session-Expires-At"
exposeHeaders := "Content-Length, Content-Type, Authorization, X-Guest-Id, X-Channel-Id, X-External-Id, X-External-Name, X-Customer-Session-Token, X-Customer-Session-Expires-At"
allowHeaders := "Origin, Content-Type, Accept, Authorization, X-Requested-With, X-Channel-Id"
exposeHeaders := "Content-Length, Content-Type, Authorization"
allowMethods := "GET, POST, PUT, PATCH, DELETE, OPTIONS"
allowedOriginSet := make(map[string]struct{}, len(allowedOrigins))
for _, origin := range allowedOrigins {
@@ -152,9 +152,7 @@ func addRouter(app *gin.Engine) {
apiGroup := app.Group("/api")
apiGroup.GET("/health", api.Health)
apiGroup.GET("/config", api.PublicConfig)
registerApiAuthRoutes(apiGroup.Group("/auth"))
registerApiChannelRoutes(apiGroup.Group("/channel"))
registerApiCustomerRoutes(apiGroup.Group("/customer"))
registerApiConversationRoutes(apiGroup.Group("/conversation", middleware.ExternalUserMiddleware))
registerApiMessageRoutes(apiGroup.Group("/message", middleware.ExternalUserMiddleware))
@@ -165,13 +163,9 @@ func addRouter(app *gin.Engine) {
dashboardGroup := app.Group("/api/dashboard", middleware.AuthMiddleware)
registerDashboardDashboardRoutes(dashboardGroup.Group("/dashboard"))
registerDashboardUserRoutes(dashboardGroup.Group("/user"))
registerDashboardCompanyRoutes(dashboardGroup.Group("/company"))
registerDashboardCustomerRoutes(dashboardGroup.Group("/customer"))
registerDashboardCustomerContactRoutes(dashboardGroup.Group("/customer-contact"))
registerDashboardRoleRoutes(dashboardGroup.Group("/role"))
registerDashboardPermissionRoutes(dashboardGroup.Group("/permission"))
registerDashboardSessionRoutes(dashboardGroup.Group("/session"))
registerDashboardTagRoutes(dashboardGroup.Group("/tag"))
registerDashboardConversationRoutes(dashboardGroup.Group("/conversation"))
registerDashboardTicketRoutes(dashboardGroup.Group("/ticket"))
+18 -24
View File
@@ -7,7 +7,7 @@ import (
"strings"
"testing"
"agent-desk/internal/pkg/config"
"code.tczkiot.com/wlw/ai-agent/internal/pkg/config"
)
func TestNewServerRegistersGinRoutes(t *testing.T) {
@@ -31,16 +31,8 @@ func TestNewServerRegistersGinRoutes(t *testing.T) {
}
expected := []string{
http.MethodPost + " /api/auth/login",
http.MethodGet + " /api/config",
http.MethodGet + " /api/health",
http.MethodGet + " /api/auth/oidc_login",
http.MethodGet + " /api/auth/oidc_callback",
http.MethodPost + " /api/auth/oidc_exchange",
http.MethodGet + " /api/auth/profile",
http.MethodGet + " /api/dashboard/user/list",
http.MethodGet + " /api/dashboard/user/:id",
http.MethodPost + " /api/dashboard/user/create",
http.MethodPost + " /api/dashboard/conversation/send_message",
http.MethodGet + " /api/dashboard/ai-workflow/default-definition",
http.MethodGet + " /api/dashboard/ai-workflow/template/list",
@@ -61,6 +53,20 @@ func TestNewServerRegistersGinRoutes(t *testing.T) {
t.Fatalf("expected route %s to be registered", route)
}
}
removed := []string{
http.MethodPost + " /api/auth/login",
http.MethodGet + " /api/auth/profile",
http.MethodGet + " /api/dashboard/user/list",
http.MethodGet + " /api/dashboard/role/list",
http.MethodGet + " /api/dashboard/permission/list",
http.MethodGet + " /api/dashboard/session/list",
}
for _, route := range removed {
if routes[route] {
t.Fatalf("removed local auth route %s is still registered", route)
}
}
}
func TestNewServerHealthEndpointIsPublic(t *testing.T) {
@@ -114,10 +120,6 @@ func TestNewServerExposesPublicConfig(t *testing.T) {
WxWork: config.WxWorkConfig{
Enabled: true,
},
OIDC: config.OIDCConfig{
Enabled: false,
ClientSecret: "must-not-leak",
},
})
app, err := NewServer()
@@ -135,9 +137,7 @@ func TestNewServerExposesPublicConfig(t *testing.T) {
var body struct {
Success bool `json:"success"`
Data struct {
Language string `json:"language"`
WxWorkEnabled bool `json:"wxworkEnabled"`
OIDCEnabled bool `json:"oidcEnabled"`
Language string `json:"language"`
} `json:"data"`
}
if err := json.Unmarshal(rec.Body.Bytes(), &body); err != nil {
@@ -149,14 +149,8 @@ func TestNewServerExposesPublicConfig(t *testing.T) {
if body.Data.Language != "zh-CN" {
t.Fatalf("language=%q want zh-CN", body.Data.Language)
}
if !body.Data.WxWorkEnabled {
t.Fatalf("wxworkEnabled=false want true")
}
if body.Data.OIDCEnabled {
t.Fatalf("oidcEnabled=true want false")
}
if strings.Contains(rec.Body.String(), "must-not-leak") {
t.Fatalf("response leaked sensitive OIDC config: %s", rec.Body.String())
if strings.Contains(rec.Body.String(), "wxworkEnabled") || strings.Contains(rec.Body.String(), "oidcEnabled") {
t.Fatalf("response still exposes removed login options: %s", rec.Body.String())
}
}