mirror of
https://gitee.com/wanwujie/sub2api
synced 2026-04-05 16:00:21 +08:00
Add a system-wide "Backend Mode" that disables user self-registration and self-service while keeping admin panel and API gateway fully functional. When enabled, only admin can log in; all user-facing routes return 403. Backend: - New setting key `backend_mode_enabled` with atomic cached reads (60s TTL) - BackendModeUserGuard middleware blocks non-admin authenticated routes - BackendModeAuthGuard middleware blocks registration/password-reset auth routes - Login/Login2FA/RefreshToken handlers reject non-admin when enabled - TokenPairWithUser struct for role-aware token refresh - 20 unit tests (middleware + service layer) Frontend: - Router guards redirect unauthenticated users to /login - Admin toggle in Settings page - Login page hides register link and footer in backend mode - 9 unit tests for router guard logic - i18n support (en/zh) 27 files changed, 833 insertions(+), 17 deletions(-) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
52 lines
1.6 KiB
Go
52 lines
1.6 KiB
Go
package middleware
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/Wei-Shaw/sub2api/internal/pkg/response"
|
|
"github.com/Wei-Shaw/sub2api/internal/service"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// BackendModeUserGuard blocks non-admin users from accessing user routes when backend mode is enabled.
|
|
// Must be placed AFTER JWT auth middleware so that the user role is available in context.
|
|
func BackendModeUserGuard(settingService *service.SettingService) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
if settingService == nil || !settingService.IsBackendModeEnabled(c.Request.Context()) {
|
|
c.Next()
|
|
return
|
|
}
|
|
role, _ := GetUserRoleFromContext(c)
|
|
if role == "admin" {
|
|
c.Next()
|
|
return
|
|
}
|
|
response.Forbidden(c, "Backend mode is active. User self-service is disabled.")
|
|
c.Abort()
|
|
}
|
|
}
|
|
|
|
// BackendModeAuthGuard selectively blocks auth endpoints when backend mode is enabled.
|
|
// Allows: login, login/2fa, logout, refresh (admin needs these).
|
|
// Blocks: register, forgot-password, reset-password, OAuth, etc.
|
|
func BackendModeAuthGuard(settingService *service.SettingService) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
if settingService == nil || !settingService.IsBackendModeEnabled(c.Request.Context()) {
|
|
c.Next()
|
|
return
|
|
}
|
|
path := c.Request.URL.Path
|
|
// Allow login, 2FA, logout, refresh, public settings
|
|
allowedSuffixes := []string{"/auth/login", "/auth/login/2fa", "/auth/logout", "/auth/refresh"}
|
|
for _, suffix := range allowedSuffixes {
|
|
if strings.HasSuffix(path, suffix) {
|
|
c.Next()
|
|
return
|
|
}
|
|
}
|
|
response.Forbidden(c, "Backend mode is active. Registration and self-service auth flows are disabled.")
|
|
c.Abort()
|
|
}
|
|
}
|