优化结构

This commit is contained in:
Yvan
2026-08-28 10:51:19 +08:00
parent fec3820464
commit 5b17f47141
12 changed files with 63 additions and 31 deletions
+7 -4
View File
@@ -13,9 +13,12 @@ type API struct {
Description string
APIGroup string
Method string
OrderKey string
Desc bool
StrictAll bool
}
type APIFilter struct {
Path, Description, APIGroup, Method string
OrderKey string
Desc, StrictAll bool
}
type APIRepo interface {
@@ -23,7 +26,7 @@ type APIRepo interface {
UpdateAPI(context.Context, *API) error
DeleteAPIs(context.Context, []uint) error
FindAPI(context.Context, uint) (*API, error)
ListAPIs(context.Context, int, int, *API) ([]*API, int64, error)
ListAPIs(context.Context, int, int, *APIFilter) ([]*API, int64, error)
APIRoleIDs(context.Context, string, string) ([]uint, error)
SetAPIRoles(context.Context, string, string, []uint) error
CheckPolicyStore(context.Context) error
+6 -1
View File
@@ -152,7 +152,12 @@ func (uc *AuthenticationUsecase) Login(ctx context.Context, attempt *LoginAttemp
return nil, fmt.Errorf("%w: %v", ErrLoginState, cacheErr)
}
}
return &AuthenticationResult{User: user, Token: issued.Value, ExpiresAt: issued.ExpiresAt, NeedChangePassword: user.MustChangePassword}, nil
// AuthenticationResult crosses the biz/service boundary; never retain the
// credential hash in the user object returned to transport code. Keep the
// repository-owned value untouched in case another caller shares it.
resultUser := *user
resultUser.Password = ""
return &AuthenticationResult{User: &resultUser, Token: issued.Value, ExpiresAt: issued.ExpiresAt, NeedChangePassword: resultUser.MustChangePassword}, nil
}
func userHasAuthority(user *User, authorityID uint) bool {
@@ -140,6 +140,23 @@ func TestLoginRecordsSuccessBeforeMultipointCacheFailure(t *testing.T) {
}
}
func TestLoginResultDoesNotExposePasswordHash(t *testing.T) {
hash, err := bcrypt.GenerateFromPassword([]byte("secret"), bcrypt.MinCost)
if err != nil {
t.Fatal(err)
}
user := &User{ID: 1, Username: "admin", Password: string(hash), AuthorityID: 888, Enable: 1}
security := NewSecurityUsecase(&authenticationSecurityRepo{}, &authenticationCache{}, &authenticationSettings{}, nil)
uc := NewAuthenticationUsecase(NewUserUsecase(&authenticationUserRepo{user: user}), security, &authenticationIssuer{}, nil)
result, err := uc.Login(context.Background(), &LoginAttempt{Username: "admin", Password: "secret", IP: "127.0.0.1"})
if err != nil {
t.Fatal(err)
}
if result.User.Password != "" {
t.Fatalf("authentication result retained password hash")
}
}
func TestRecordLoginAllowsMissingAuditRecorder(t *testing.T) {
uc := &AuthenticationUsecase{}
uc.recordLogin(context.Background(), &LoginAttempt{Username: "admin"}, false, "failed", 0)
+5 -3
View File
@@ -39,15 +39,17 @@ type ExportTemplate struct {
Order string
Conditions []ExportCondition
Joins []ExportJoin
StartCreatedAt *time.Time
EndCreatedAt *time.Time
}
type ExportTemplateFilter struct {
Name, TableName, TemplateID string
StartCreatedAt, EndCreatedAt *time.Time
}
type ExportRepo interface {
CreateExportTemplate(context.Context, *ExportTemplate) error
UpdateExportTemplate(context.Context, *ExportTemplate) error
DeleteExportTemplates(context.Context, []uint) error
FindExportTemplate(context.Context, uint, string) (*ExportTemplate, error)
ListExportTemplates(context.Context, int, int, *ExportTemplate) ([]*ExportTemplate, int64, error)
ListExportTemplates(context.Context, int, int, *ExportTemplateFilter) ([]*ExportTemplate, int64, error)
QueryExport(context.Context, *ExportTemplate, map[string]string) ([]map[string]any, string, error)
PreviewExport(context.Context, *ExportTemplate, map[string]string) (string, error)
ImportExportRows(context.Context, *ExportTemplate, []map[string]any) error