优化结构

This commit is contained in:
Yvan
2026-08-22 12:13:16 +08:00
parent d987244d0e
commit b27a66e9d3
200 changed files with 1794 additions and 1715 deletions
+4 -4
View File
@@ -2,8 +2,8 @@ package middleware
import (
"context"
"kra/internal/biz/system"
"kra/internal/biz"
"kra/internal/conf"
"kra/internal/service"
@@ -39,13 +39,13 @@ func AccessControl(runtime *conf.Runtime, access accessController) gin.HandlerFu
c.Abort()
return
}
if scope, ok := biz.DataScopeFromContext(requestContext); ok {
if scope, ok := system.DataScopeFromContext(requestContext); ok {
requestID, _ := c.Get("request_id")
scope.RequestID, _ = requestID.(string)
scope.Method, scope.Path = c.Request.Method, path
requestContext = biz.NewDataScopeContext(requestContext, scope)
requestContext = system.NewDataScopeContext(requestContext, scope)
}
requestContext = biz.NewActorContext(requestContext, biz.Actor{UserID: claims.ID, AuthorityID: claims.AuthorityID})
requestContext = system.NewActorContext(requestContext, system.Actor{UserID: claims.ID, AuthorityID: claims.AuthorityID})
c.Request = c.Request.WithContext(requestContext)
c.Next()
}
+2 -2
View File
@@ -6,6 +6,7 @@ import (
"encoding/hex"
"errors"
"io"
"kra/internal/biz/system"
"log/slog"
"mime"
"net/http"
@@ -14,7 +15,6 @@ import (
"strings"
"time"
"kra/internal/biz"
"kra/internal/conf"
"github.com/gin-gonic/gin"
@@ -33,7 +33,7 @@ func AccessLog(runtime *conf.Runtime, logger *slog.Logger, version string) gin.H
config := runtime.Admin()
bodyLimit := defaultRequestBodyLimit
if mediaUpload {
bodyLimit = biz.DefaultMaxMediaFileSize + (1 << 20)
bodyLimit = system.DefaultMaxMediaFileSize + (1 << 20)
if config != nil && config.Media != nil && config.Media.MaxFileSize > 0 {
bodyLimit = config.Media.MaxFileSize + (1 << 20)
}
+3 -3
View File
@@ -3,12 +3,12 @@ package middleware
import (
"context"
"errors"
"kra/internal/biz/system"
"net/http"
"net/http/httptest"
"strings"
"testing"
"kra/internal/biz"
"kra/internal/conf"
"github.com/gin-gonic/gin"
@@ -26,14 +26,14 @@ func (s *accessControllerStub) ContextWithDataScope(ctx context.Context, authori
if s.scopeErr != nil {
return ctx, s.scopeErr
}
return biz.NewDataScopeContext(ctx, biz.DataScope{UserID: userID, AuthorityID: authorityID, Scope: 1, All: true}), nil
return system.NewDataScopeContext(ctx, system.DataScope{UserID: userID, AuthorityID: authorityID, Scope: 1, All: true}), nil
}
func TestAccessControlFailsClosedWhenDataScopeResolutionFails(t *testing.T) {
gin.SetMode(gin.TestMode)
engine := gin.New()
engine.Use(func(c *gin.Context) {
c.Set(claimsKey, &biz.AuthClaims{ID: 7, AuthorityID: 888})
c.Set(claimsKey, &system.AuthClaims{ID: 7, AuthorityID: 888})
c.Next()
})
engine.Use(AccessControl(conf.NewRuntime(nil, &conf.AdminBackend{}), &accessControllerStub{scopeErr: errors.New("database unavailable")}))
+10 -11
View File
@@ -3,12 +3,11 @@ package middleware
import (
"context"
"errors"
"kra/internal/biz/system"
"net/http"
"strconv"
"strings"
"kra/internal/biz"
"github.com/gin-gonic/gin"
"golang.org/x/sync/singleflight"
)
@@ -18,7 +17,7 @@ const claimsKey = "admin_claims"
var refreshTokens singleflight.Group
type TokenAuthenticator interface {
AuthenticateToken(context.Context, string) (*biz.TokenAuthentication, error)
AuthenticateToken(context.Context, string) (*system.TokenAuthentication, error)
}
func Auth(auth TokenAuthenticator) gin.HandlerFunc {
@@ -54,7 +53,7 @@ func authenticate(c *gin.Context, auth TokenAuthenticator, allowQueryToken bool)
NoAuth(c, tokenErrorMessage(err))
return false
}
authentication, ok := value.(*biz.TokenAuthentication)
authentication, ok := value.(*system.TokenAuthentication)
if !ok || authentication == nil || authentication.Claims == nil {
SetTokenCookie(c, "", -1)
NoAuth(c, "无法处理此token")
@@ -95,23 +94,23 @@ func requestToken(c *gin.Context, allowQueryToken bool) string {
func tokenErrorMessage(err error) string {
message := "无法处理此token"
switch {
case errors.Is(err, biz.ErrTokenExpired):
case errors.Is(err, system.ErrTokenExpired):
message = "登录已过期,请重新登录"
case errors.Is(err, biz.ErrTokenMalformed):
case errors.Is(err, system.ErrTokenMalformed):
message = "这不是一个token"
case errors.Is(err, biz.ErrTokenSignatureInvalid):
case errors.Is(err, system.ErrTokenSignatureInvalid):
message = "无效签名"
case errors.Is(err, biz.ErrTokenNotValidYet):
case errors.Is(err, system.ErrTokenNotValidYet):
message = "token尚未激活"
case errors.Is(err, biz.ErrTokenDisabled):
case errors.Is(err, system.ErrTokenDisabled):
message = "您的帐户异地登陆或令牌失效"
}
return message
}
func Claims(c *gin.Context) *biz.AuthClaims {
func Claims(c *gin.Context) *system.AuthClaims {
value, _ := c.Get(claimsKey)
claims, _ := value.(*biz.AuthClaims)
claims, _ := value.(*system.AuthClaims)
return claims
}
+7 -8
View File
@@ -3,32 +3,31 @@ package middleware
import (
"context"
"errors"
"kra/internal/biz/system"
"net/http"
"net/http/httptest"
"testing"
"kra/internal/biz"
"github.com/gin-gonic/gin"
)
type tokenAuthenticatorStub struct {
claims *biz.AuthClaims
claims *system.AuthClaims
err error
got string
}
func (s *tokenAuthenticatorStub) AuthenticateToken(_ context.Context, token string) (*biz.TokenAuthentication, error) {
func (s *tokenAuthenticatorStub) AuthenticateToken(_ context.Context, token string) (*system.TokenAuthentication, error) {
s.got = token
if s.err != nil {
return nil, s.err
}
return &biz.TokenAuthentication{Claims: s.claims}, nil
return &system.TokenAuthentication{Claims: s.claims}, nil
}
func TestAuthenticateWebSocketAcceptsQueryToken(t *testing.T) {
gin.SetMode(gin.TestMode)
stub := &tokenAuthenticatorStub{claims: &biz.AuthClaims{ID: 7}}
stub := &tokenAuthenticatorStub{claims: &system.AuthClaims{ID: 7}}
recorder := httptest.NewRecorder()
context, _ := gin.CreateTestContext(recorder)
context.Request = httptest.NewRequest(http.MethodGet, "/ws?token=query-token", nil)
@@ -46,7 +45,7 @@ func TestAuthenticateWebSocketAcceptsQueryToken(t *testing.T) {
func TestHTTPAuthDoesNotAcceptQueryToken(t *testing.T) {
gin.SetMode(gin.TestMode)
stub := &tokenAuthenticatorStub{claims: &biz.AuthClaims{ID: 7}}
stub := &tokenAuthenticatorStub{claims: &system.AuthClaims{ID: 7}}
engine := gin.New()
called := false
engine.GET("/protected", Auth(stub), func(c *gin.Context) { called = true })
@@ -60,7 +59,7 @@ func TestHTTPAuthDoesNotAcceptQueryToken(t *testing.T) {
func TestAuthenticateWebSocketSupportsBearerHeaderAndReportsInvalidToken(t *testing.T) {
gin.SetMode(gin.TestMode)
stub := &tokenAuthenticatorStub{claims: &biz.AuthClaims{ID: 7}}
stub := &tokenAuthenticatorStub{claims: &system.AuthClaims{ID: 7}}
context, _ := gin.CreateTestContext(httptest.NewRecorder())
context.Request = httptest.NewRequest(http.MethodGet, "/ws", nil)
context.Request.Header.Set("Authorization", "Bearer header-token")
@@ -3,13 +3,13 @@ package middleware
import (
"context"
"errors"
"kra/internal/biz/system"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"kra/internal/biz"
"kra/internal/service"
"github.com/gin-gonic/gin"
@@ -17,10 +17,10 @@ import (
type rateLimitSecurityRepo struct{}
func (rateLimitSecurityRepo) SecurityConfig(context.Context) (*biz.SecurityConfig, error) {
return &biz.SecurityConfig{LimitEnable: true, LimitWindow: 60, LimitCount: 1}, nil
func (rateLimitSecurityRepo) SecurityConfig(context.Context) (*system.SecurityConfig, error) {
return &system.SecurityConfig{LimitEnable: true, LimitWindow: 60, LimitCount: 1}, nil
}
func (rateLimitSecurityRepo) SaveSecurityConfig(context.Context, *biz.SecurityConfig) error {
func (rateLimitSecurityRepo) SaveSecurityConfig(context.Context, *system.SecurityConfig) error {
return nil
}
func (rateLimitSecurityRepo) BackfillPasswordUpdatedAt(context.Context, time.Time) error {
@@ -38,7 +38,7 @@ func (c rateLimitCache) Increment(context.Context, string, time.Duration) (int64
func TestSecurityRateLimitMatchesResponseContract(t *testing.T) {
gin.SetMode(gin.TestMode)
settings := service.NewSecurityService(biz.NewSecurityUsecase(rateLimitSecurityRepo{}, rateLimitCache{}, nil, nil))
settings := service.NewSecurityService(system.NewSecurityUsecase(rateLimitSecurityRepo{}, rateLimitCache{}, nil, nil))
engine := gin.New()
engine.Use(SecurityRateLimit(settings))
engine.POST("/base/login", func(c *gin.Context) { c.Status(http.StatusNoContent) })
@@ -56,7 +56,7 @@ func TestSecurityRateLimitMatchesResponseContract(t *testing.T) {
func TestSecurityRateLimitFailsClosedWhenCacheIsUnavailable(t *testing.T) {
gin.SetMode(gin.TestMode)
settings := service.NewSecurityService(biz.NewSecurityUsecase(rateLimitSecurityRepo{}, rateLimitCache{err: errors.New("cache unavailable")}, nil, nil))
settings := service.NewSecurityService(system.NewSecurityUsecase(rateLimitSecurityRepo{}, rateLimitCache{err: errors.New("cache unavailable")}, nil, nil))
engine := gin.New()
called := false
engine.Use(SecurityRateLimit(settings))