diff --git a/server/admin/internal/modules/externaladmin/handler.go b/server/admin/internal/modules/externaladmin/handler.go index 2d5f24a6..0f958992 100644 --- a/server/admin/internal/modules/externaladmin/handler.go +++ b/server/admin/internal/modules/externaladmin/handler.go @@ -236,15 +236,6 @@ func (h *Handler) ResetPassword(c *gin.Context) { response.OK(c, account) } -func (h *Handler) ListApps(c *gin.Context) { - apps, err := h.service.ListApps(c.Request.Context()) - if err != nil { - response.ServerError(c, "获取 App 列表失败") - return - } - response.OK(c, gin.H{"items": apps, "total": len(apps)}) -} - func (h *Handler) Login(c *gin.Context) { // The global App middleware supplies the main-admin default before this anonymous // route runs. No tenant is authoritative until a credential row resolves, so do diff --git a/server/admin/internal/modules/externaladmin/routes.go b/server/admin/internal/modules/externaladmin/routes.go index bc4ad821..b44acb63 100644 --- a/server/admin/internal/modules/externaladmin/routes.go +++ b/server/admin/internal/modules/externaladmin/routes.go @@ -49,7 +49,6 @@ func RegisterExternalRoutes(api *gin.RouterGroup, h *Handler, handlers BusinessH // service workers or intermediary proxies. This middleware runs before session // auth so 4xx/5xx responses carry the same protection as successful responses. auth.Use(noStore()) - auth.GET("/apps", h.ListApps) auth.POST("/login", h.Login) protectedAuth := auth.Group("") diff --git a/server/admin/internal/modules/externaladmin/routes_security_test.go b/server/admin/internal/modules/externaladmin/routes_security_test.go index e55ffb63..76ca970d 100644 --- a/server/admin/internal/modules/externaladmin/routes_security_test.go +++ b/server/admin/internal/modules/externaladmin/routes_security_test.go @@ -43,3 +43,16 @@ func TestExternalAuthResponsesAlwaysDisableCachingIncludingErrors(t *testing.T) }) } } + +func TestExternalAuthDoesNotExposeAppCatalogBeforeLogin(t *testing.T) { + gin.SetMode(gin.TestMode) + engine := gin.New() + RegisterExternalRoutes(engine.Group("/api/v1"), New(nil, nil, Config{}, nil), BusinessHandlers{}) + + request := httptest.NewRequest(http.MethodGet, "/api/v1/external/auth/apps", nil) + responseRecorder := httptest.NewRecorder() + engine.ServeHTTP(responseRecorder, request) + if responseRecorder.Code != http.StatusNotFound { + t.Fatalf("anonymous App catalog status=%d body=%s", responseRecorder.Code, responseRecorder.Body.String()) + } +} diff --git a/server/admin/internal/modules/externaladmin/service.go b/server/admin/internal/modules/externaladmin/service.go index 02d5b283..30ca306b 100644 --- a/server/admin/internal/modules/externaladmin/service.go +++ b/server/admin/internal/modules/externaladmin/service.go @@ -65,30 +65,6 @@ func NewService(db *gorm.DB, userDB *sql.DB, cfg Config) *Service { return &Service{db: db, userDB: userDB, cfg: cfg, dummyHash: dummyHash} } -func (s *Service) ListApps(ctx context.Context) ([]App, error) { - if s.userDB == nil { - return nil, errors.New("user mysql is not configured") - } - rows, err := s.userDB.QueryContext(ctx, ` - SELECT app_code, app_name, logo_url - FROM apps - WHERE status = 'active' - ORDER BY app_name ASC, app_code ASC`) - if err != nil { - return nil, err - } - defer rows.Close() - apps := []App{} - for rows.Next() { - var app App - if err := rows.Scan(&app.AppCode, &app.AppName, &app.LogoURL); err != nil { - return nil, err - } - apps = append(apps, app) - } - return apps, rows.Err() -} - func (s *Service) ResolveTarget(ctx context.Context, appCode string, target string) (LinkedUser, error) { appCode = normalizeAppCode(appCode) target = strings.TrimSpace(target)