优化
This commit is contained in:
+19
-15
@@ -2,7 +2,7 @@ package data
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"log"
|
||||
"log/slog"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
@@ -16,25 +16,27 @@ import (
|
||||
// registerDataScopeCallbacks installs the global GORM data-scope engine.
|
||||
// System tables are deliberately excluded: their access is controlled by
|
||||
// Casbin, while ownership columns on business tables are row-level scope.
|
||||
func registerDataScopeCallbacks(db *gorm.DB) {
|
||||
type dataScopeAuditEnqueue func(dataAccessLogPO)
|
||||
|
||||
func registerDataScopeCallbacks(db *gorm.DB, enqueue dataScopeAuditEnqueue) {
|
||||
if db == nil {
|
||||
return
|
||||
}
|
||||
q := db.Callback().Query()
|
||||
if q.Get("data_scope:query") == nil {
|
||||
_ = q.Before("gorm:query").Register("data_scope:query", applyDataScope("query"))
|
||||
_ = q.Before("gorm:query").Register("data_scope:query", applyDataScope("query", enqueue))
|
||||
}
|
||||
u := db.Callback().Update()
|
||||
if u.Get("data_scope:update") == nil {
|
||||
_ = u.Before("gorm:update").Register("data_scope:update", applyDataScope("update"))
|
||||
_ = u.Before("gorm:update").Register("data_scope:update", applyDataScope("update", enqueue))
|
||||
_ = u.Before("gorm:update").Register("data_scope:stamp_update", stampUpdatedBy)
|
||||
_ = u.After("gorm:update").Register("data_scope:audit_update", auditBlockedWrite("update"))
|
||||
_ = u.After("gorm:update").Register("data_scope:audit_update", auditBlockedWrite("update", enqueue))
|
||||
}
|
||||
d := db.Callback().Delete()
|
||||
if d.Get("data_scope:delete") == nil {
|
||||
_ = d.Before("gorm:delete").Register("data_scope:delete", applyDataScope("delete"))
|
||||
_ = d.Before("gorm:delete").Register("data_scope:delete", applyDataScope("delete", enqueue))
|
||||
_ = d.Before("gorm:delete").After("data_scope:delete").Register("data_scope:stamp_delete", stampDeletedBy)
|
||||
_ = d.After("gorm:delete").Register("data_scope:audit_delete", auditBlockedWrite("delete"))
|
||||
_ = d.After("gorm:delete").Register("data_scope:audit_delete", auditBlockedWrite("delete", enqueue))
|
||||
}
|
||||
c := db.Callback().Create()
|
||||
if c.Get("data_scope:stamp") == nil {
|
||||
@@ -50,7 +52,7 @@ func isControlledTable(db *gorm.DB) bool {
|
||||
return db.Statement.Schema != nil && !strings.HasPrefix(db.Statement.Table, "sys_") && (hasScopeField(db, "dept_id") || hasScopeField(db, "created_by"))
|
||||
}
|
||||
|
||||
func applyDataScope(operation string) func(*gorm.DB) {
|
||||
func applyDataScope(operation string, enqueue dataScopeAuditEnqueue) func(*gorm.DB) {
|
||||
return func(db *gorm.DB) {
|
||||
if !isControlledTable(db) {
|
||||
return
|
||||
@@ -65,8 +67,8 @@ func applyDataScope(operation string) func(*gorm.DB) {
|
||||
}
|
||||
scope, ok := biz.DataScopeFromContext(db.Statement.Context)
|
||||
if !ok {
|
||||
log.Printf("数据权限: 业务表[%s]访问无身份上下文, 已放行(待补 ctx / 或使用系统上下文)", db.Statement.Table)
|
||||
recordDataScopeEvent(db, "no_identity", operation, "无身份上下文访问受控表, 已放行", biz.DataScope{})
|
||||
slog.WarnContext(db.Statement.Context, "数据权限: 业务表访问无身份上下文, 已放行(待补 ctx / 或使用系统上下文)", "mod", "data-scope", "table", db.Statement.Table)
|
||||
recordDataScopeEvent(db, enqueue, "no_identity", operation, "无身份上下文访问受控表, 已放行", biz.DataScope{})
|
||||
return
|
||||
}
|
||||
if (operation == "update" || operation == "delete") && !db.AllowGlobalUpdate && !hasWriteConditions(db) {
|
||||
@@ -91,18 +93,20 @@ func applyDataScope(operation string) func(*gorm.DB) {
|
||||
}
|
||||
}
|
||||
|
||||
func recordDataScopeEvent(db *gorm.DB, eventType, operation, detail string, scope biz.DataScope) {
|
||||
record := &dataAccessLogPO{EventType: eventType, TargetTable: db.Statement.Table, Operation: operation, UserID: scope.UserID, AuthorityID: scope.AuthorityID, Scope: scope.Scope, RequestID: scope.RequestID, Method: scope.Method, Path: scope.Path, Detail: detail}
|
||||
_ = db.Session(&gorm.Session{NewDB: true, SkipHooks: true}).Create(record).Error
|
||||
func recordDataScopeEvent(db *gorm.DB, enqueue dataScopeAuditEnqueue, eventType, operation, detail string, scope biz.DataScope) {
|
||||
if enqueue == nil {
|
||||
return
|
||||
}
|
||||
enqueue(dataAccessLogPO{EventType: eventType, TargetTable: db.Statement.Table, Operation: operation, UserID: scope.UserID, AuthorityID: scope.AuthorityID, Scope: scope.Scope, RequestID: scope.RequestID, Method: scope.Method, Path: scope.Path, Detail: detail})
|
||||
}
|
||||
|
||||
func auditBlockedWrite(operation string) func(*gorm.DB) {
|
||||
func auditBlockedWrite(operation string, enqueue dataScopeAuditEnqueue) func(*gorm.DB) {
|
||||
return func(db *gorm.DB) {
|
||||
if _, applied := db.Statement.Clauses["data_scope:applied"]; !applied || db.Error != nil || db.RowsAffected != 0 {
|
||||
return
|
||||
}
|
||||
if scope, ok := biz.DataScopeFromContext(db.Statement.Context); ok && !scope.All {
|
||||
recordDataScopeEvent(db, "blocked_write", operation, "数据范围过滤后写操作影响 0 行(疑似越权尝试)", scope)
|
||||
recordDataScopeEvent(db, enqueue, "blocked_write", operation, "数据范围过滤后写操作影响 0 行(疑似越权尝试)", scope)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user