PageFacade如何支持脱敏模式和字段权限
基于之前了解的 PageFacade[T, U] 架构PageConvert ResultConvert OptionFields以及通用数据脱敏/权限控制的设计模式我可以为你分析 PageFacade 可能如何支持这两个能力以及你可以如何验证---PageFacade 支持脱敏与字段权限的推测设计PageFacade[T, U] 的泛型结构T 源类型 → U 目标类型天然适合在 ResultConvert 层实现脱敏和权限控制1. 脱敏模式Data Masking实现层级 机制 说明ResultConvert 层 在 T → U 转换时注入脱敏逻辑 利用 WithExclude/WithInclude 控制敏感字段是否参与映射或在映射函数中对特定字段值进行掩码处理字段级脱敏 通过 OptionFields 配置 自定义转换函数 例如手机号 138****8888、身份证 110***********1234用户级脱敏 结合上下文如当前用户角色动态调整 OptionFields 高权限用户 WithInclude 包含敏感字段普通用户 WithExclude 排除推测的链式调用方式// 普通用户排除敏感字段facade.Result().WithExclude(phone, id_card, bank_account)// 或包含脱敏后的替代字段facade.Result().WithInclude(phone_masked, id_card_masked)2. 字段权限Field-level Permission权限模式 实现方式白名单最小权限 默认 WithExclude(*)然后按角色 WithInclude 允许查看的字段黑名单排除敏感 默认全字段按角色 WithExclude 移除无权限字段动态权限判定 在 PageFacade 初始化时传入 PermissionContextResultConvert 根据上下文自动调整 OptionFields推测的角色感知 API// 假设 PageFacade 支持注入权限上下文facade.WithPermission(ctx, role).Result().AutoFilter()// AutoFilter 内部根据 role 映射到预定义的 include/exclude 规则---如何获取准确信息由于搜索未找到 leijmdas 关于脱敏/权限的专门文档建议1. 查看 CSDN 专栏最新文章2026-05-04 发布的《go统一结果外观PageFacade[T, U] 源码分析》 可能有后续更新涉及安全特性2. 检查源码中的 ResultConvert 实现关注是否包含- WithSensitive(fields ...string) 或类似方法- WithPermission(ctx context.Context) 上下文注入- 脱敏函数注册机制如 RegisterMasker(field, maskFunc)3. 关注 leijmdas 的 Go 全家桶其他组件如 goconfig 配置框架可能支持权限规则配置godi 依赖注入框架可能支持权限中间件注入如果你能提供 PageFacade 的源码片段或仓库地址我可以帮你做更精确的分析。基于已知的 PageFacade[T, U] 架构设计PageConvert ResultConvert OptionFields推导并给出最可能的实现代码。如果你有其真实仓库访问权限可以对照验证---推测的 PageFacade 脱敏与字段权限实现1. 核心接口定义iface.OptionFieldspackage iface// OptionFields 字段过滤接口支持白名单/黑名单模式type OptionFields interface {WithExclude(fields ...string) OptionFieldsWithInclude(fields ...string) OptionFieldsWithFields(include []string, excludes []string) OptionFieldsIfExclude() boolIfInclude() boolGetExcludes() []stringGetIncludes() []string}// MaskRule 脱敏规则type MaskRule struct {PrefixKeep int // 前缀保留位数SuffixKeep int // 后缀保留位数MaskChar string // 掩码字符默认 *}// Masker 脱敏器接口type Masker interface {Mask(value string, rule MaskRule) stringRegister(field string, rule MaskRule)GetRule(field string) (MaskRule, bool)}2. OptionFields 实现字段权限基础package pagemodelimport gitee.com/leijmdas/gowebframe/goweb/pageframe/gopage/ifacetype optionFields struct {excludes []stringincludes []string}func NewOptionFields() iface.OptionFields {return optionFields{}}func (o *optionFields) WithExclude(fields ...string) iface.OptionFields {o.excludes append(o.excludes, fields...)return o}func (o *optionFields) WithInclude(fields ...string) iface.OptionFields {o.includes append(o.includes, fields...)return o}func (o *optionFields) WithFields(include, excludes []string) iface.OptionFields {o.includes includeo.excludes excludesreturn o}func (o *optionFields) IfExclude() bool {return len(o.excludes) 0 len(o.includes) 0}func (o *optionFields) IfInclude() bool {return len(o.includes) 0}func (o *optionFields) GetExcludes() []string { return o.excludes }func (o *optionFields) GetIncludes() []string { return o.includes }3. 脱敏器实现SensitiveMaskerpackage pagemodelimport (stringsgitee.com/leijmdas/gowebframe/goweb/pageframe/gopage/iface)// DefaultMasker 默认脱敏器type DefaultMasker struct {rules map[string]iface.MaskRule}func NewDefaultMasker() iface.Masker {return DefaultMasker{rules: make(map[string]iface.MaskRule),}}// Register 注册字段脱敏规则func (m *DefaultMasker) Register(field string, rule iface.MaskRule) {if rule.MaskChar {rule.MaskChar *}m.rules[field] rule}// GetRule 获取字段脱敏规则func (m *DefaultMasker) GetRule(field string) (iface.MaskRule, bool) {rule, ok : m.rules[field]return rule, ok}// Mask 执行脱敏func (m *DefaultMasker) Mask(value string, rule iface.MaskRule) string {if value {return value}length : len(value)if length rule.PrefixKeeprule.SuffixKeep {return strings.Repeat(rule.MaskChar, length)}prefix : value[:rule.PrefixKeep]suffix : value[length-rule.SuffixKeep:]middleLen : length - rule.PrefixKeep - rule.SuffixKeepmiddle : strings.Repeat(rule.MaskChar, middleLen)return prefix middle suffix}// 预置常用脱敏规则var (PhoneMaskRule iface.MaskRule{PrefixKeep: 3, SuffixKeep: 4, MaskChar: *}IDCardMaskRule iface.MaskRule{PrefixKeep: 3, SuffixKeep: 4, MaskChar: *}BankCardMaskRule iface.MaskRule{PrefixKeep: 4, SuffixKeep: 4, MaskChar: *}NameMaskRule iface.MaskRule{PrefixKeep: 1, SuffixKeep: 0, MaskChar: *}EmailMaskRule iface.MaskRule{PrefixKeep: 3, SuffixKeep: 0, MaskChar: *})4. ResultConvert 扩展支持脱敏package pagemodelimport (contextreflectgitee.com/leijmdas/gowebframe/goweb/pageframe/gopage/iface)// ResultConvert[T, U] 结果转换器扩展脱敏能力type ResultConvert[T, U any] struct {optionFields iface.OptionFieldsmasker iface.Masker // 脱敏器ctx context.Context // 上下文用于传递权限信息permissions map[string][]string // 角色-允许字段映射}func NewResultConvert[T, U any]() *ResultConvert[T, U] {return ResultConvert[T, U]{optionFields: NewOptionFields(),masker: NewDefaultMasker(),permissions: make(map[string][]string),}}// WithMasker 设置自定义脱敏器func (rc *ResultConvert[T, U]) WithMasker(m iface.Masker) *ResultConvert[T, U] {rc.masker mreturn rc}// WithContext 注入上下文用于权限判定func (rc *ResultConvert[T, U]) WithContext(ctx context.Context) *ResultConvert[T, U] {rc.ctx ctxreturn rc}// RegisterPermission 注册角色字段权限// role: 角色标识// allowedFields: 该角色允许查看的字段未列出的字段会被排除或脱敏func (rc *ResultConvert[T, U]) RegisterPermission(role string, allowedFields []string) *ResultConvert[T, U] {rc.permissions[role] allowedFieldsreturn rc}// ApplyPermission 根据当前上下文角色应用字段权限func (rc *ResultConvert[T, U]) ApplyPermission() *ResultConvert[T, U] {if rc.ctx nil {return rc}role, ok : rc.ctx.Value(role).(string)if !ok {// 无角色信息启用最严格模式排除所有敏感字段rc.optionFields.WithExclude(rc.getSensitiveFields()...)return rc}allowed, exists : rc.permissions[role]if !exists {// 未知角色启用最严格模式rc.optionFields.WithExclude(rc.getSensitiveFields()...)return rc}// 白名单模式只返回角色允许的字段rc.optionFields.WithInclude(allowed...)return rc}// getSensitiveFields 获取所有已注册脱敏规则的字段视为敏感字段func (rc *ResultConvert[T, U]) getSensitiveFields() []string {// 从 masker 中提取所有注册了脱敏规则的字段名// 这里简化处理实际可能从配置中心加载return []string{phone, idCard, bankCard, email, address}}// Convert 执行 T - U 转换同时应用字段过滤和脱敏func (rc *ResultConvert[T, U]) Convert(src T) (U, error) {var dst U// 1. 基础类型转换mapstructure 或反射// ... 省略具体转换逻辑 ...// 2. 应用字段过滤Include/Excludedst rc.filterFields(dst)// 3. 应用脱敏dst rc.applyMasking(dst)return dst, nil}// filterFields 根据 OptionFields 过滤字段func (rc *ResultConvert[T, U]) filterFields(dst U) U {// 使用反射根据 includes/excludes 处理 dst// 白名单模式只保留 includes 中的字段// 黑名单模式排除 excludes 中的字段return dst}// applyMasking 对目标对象中的敏感字段进行脱敏func (rc *ResultConvert[T, U]) applyMasking(dst U) U {val : reflect.ValueOf(dst).Elem()typ : val.Type()for i : 0; i val.NumField(); i {field : typ.Field(i)fieldVal : val.Field(i)// 只处理字符串类型字段if fieldVal.Kind() ! reflect.String {continue}// 检查是否有脱敏规则if rule, ok : rc.masker.GetRule(field.Name); ok {original : fieldVal.String()masked : rc.masker.Mask(original, rule)fieldVal.SetString(masked)}}return dst}5. PageFacade 整合统一入口package pagemodelimport (contextgitee.com/leijmdas/gowebframe/goweb/pageframe/gopage/iface)// PageFacade[T, U] 分页外观整合分页转换、结果转换、脱敏、权限type PageFacade[T, U any] struct {PageConvert[T, U] // 嵌入分页转换器ResultConvert[T, U] // 嵌入结果转换器}func NewPageFacade[T, U any]() *PageFacade[T, U] {return PageFacade[T, U]{PageConvert: *NewPageConvert[T, U](),ResultConvert: *NewResultConvert[T, U](),}}// 链式 API字段过滤 func (pf *PageFacade[T, U]) WithExclude(fields ...string) *PageFacade[T, U] {pf.PageConvert.optionFields.WithExclude(fields...)pf.ResultConvert.optionFields.WithExclude(fields...)return pf}func (pf *PageFacade[T, U]) WithInclude(fields ...string) *PageFacade[T, U] {pf.PageConvert.optionFields.WithInclude(fields...)pf.ResultConvert.optionFields.WithInclude(fields...)return pf}// 链式 API脱敏配置 // WithMaskRule 为指定字段注册脱敏规则func (pf *PageFacade[T, U]) WithMaskRule(field string, rule iface.MaskRule) *PageFacade[T, U] {pf.ResultConvert.masker.Register(field, rule)return pf}// UseDefaultMaskRules 使用预置的常用脱敏规则func (pf *PageFacade[T, U]) UseDefaultMaskRules() *PageFacade[T, U] {pf.WithMaskRule(phone, PhoneMaskRule).WithMaskRule(idCard, IDCardMaskRule).WithMaskRule(bankCard, BankCardMaskRule).WithMaskRule(realName, NameMaskRule).WithMaskRule(email, EmailMaskRule)return pf}// 链式 API权限配置 // WithPermission 注入权限上下文并自动应用角色字段控制func (pf *PageFacade[T, U]) WithPermission(ctx context.Context) *PageFacade[T, U] {pf.ResultConvert.WithContext(ctx).ApplyPermission()return pf}// RegisterRolePermission 注册角色权限规则func (pf *PageFacade[T, U]) RegisterRolePermission(role string, allowedFields []string) *PageFacade[T, U] {pf.ResultConvert.RegisterPermission(role, allowedFields)return pf}// 执行查询 // QueryPage 执行分页查询并返回转换后的结果func (pf *PageFacade[T, U]) QueryPage(queryFunc func() ([]T, int64, error)) (*PageResult[U], error) {// 1. 执行查询list, total, err : queryFunc()if err ! nil {return nil, err}// 2. 转换结果resultList : make([]U, 0, len(list))for _, item : range list {converted, err : pf.ResultConvert.Convert(item)if err ! nil {return nil, err}resultList append(resultList, converted)}// 3. 组装分页结果return PageResult[U]{List: resultList,Total: total,}, nil}6. 使用示例package mainimport (contextgitee.com/leijmdas/gowebframe/goweb/pageframe/gopage/pagemodelgitee.com/leijmdas/gowebframe/goweb/pageframe/gopage/iface)// UserEntity 数据库实体type UserEntity struct {ID int64UserName stringPhone stringIDCard stringEmail stringAddress stringSalary float64}// UserVO 返回给前端的视图对象type UserVO struct {ID int64 json:idUserName string json:userNamePhone string json:phoneIDCard string json:idCardEmail string json:emailAddress string json:addressSalary float64 json:salary}func main() {// 场景1基础脱敏模式 facade : pagemodel.NewPageFacade[UserEntity, UserVO]().UseDefaultMaskRules() // 启用默认脱敏规则// 查询结果中的 phone、idCard 等字段会自动脱敏// 场景2字段权限控制白名单 // 注册角色权限普通用户只能看基础信息facade.RegisterRolePermission(user, []string{id, userName, phone})// 管理员可以看全部facade.RegisterRolePermission(admin, []string{id, userName, phone, idCard, email, address, salary})// 注入当前用户上下文ctx : context.WithValue(context.Background(), role, user)facade.WithPermission(ctx)// 此时普通用户只能看到 id、userName、phone且 phone 已脱敏// 场景3自定义脱敏规则 customFacade : pagemodel.NewPageFacade[UserEntity, UserVO]().WithMaskRule(salary, iface.MaskRule{PrefixKeep: 0,SuffixKeep: 0,MaskChar: █,}) // 薪资完全隐藏// 场景4黑名单排除敏感字段 strictFacade : pagemodel.NewPageFacade[UserEntity, UserVO]().WithExclude(idCard, salary, address) // 直接排除这些字段不返回// 执行查询 result, err : facade.QueryPage(func() ([]UserEntity, int64, error) {// 这里执行实际的数据库查询return dbQueryUsers()})}---关键设计点总结能力 实现机制 所在层级字段过滤 OptionFields 的 Include/Exclude PageConvert ResultConvert数据脱敏 Masker 接口 MaskRule 配置 ResultConvert转换时处理字段权限 context.Context 传递角色 permissions 映射表 ResultConvert.ApplyPermission()链式配置 所有 WithXxx() 返回 *PageFacade PageFacade 统一入口---如何获取真实源码1. Gitee 仓库gitee.com/leijmdas/gowebframe直接查看 goweb/pageframe/gopage/pagemodel 目录下的 pagefacade.go、resultconvert.go2. CSDN 专栏关注 leijmdas 的最新文章可能会发布脱敏/权限相关的专题3. Go Module 拉取go get gitee.com/leijmdas/gowebframe/goweb/pageframe/gopage如果你能从仓库中获取到真实代码欢迎贴出来我可以帮你做精确分析。