package role import ( "context" "perms-system-server/internal/middleware" "perms-system-server/internal/response" "perms-system-server/internal/svc" "perms-system-server/internal/types" "github.com/zeromicro/go-zero/core/logx" ) type RoleDetailLogic struct { logx.Logger ctx context.Context svcCtx *svc.ServiceContext } func NewRoleDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RoleDetailLogic { return &RoleDetailLogic{ Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx, } } // RoleDetail 角色详情。根据角色 ID 查询角色完整信息及其已绑定的权限 ID 列表。 func (l *RoleDetailLogic) RoleDetail(req *types.RoleDetailReq) (resp *types.RoleItem, err error) { caller := middleware.GetUserDetails(l.ctx) if caller == nil { return nil, response.ErrUnauthorized("未登录") } // 审计 M-N3:合并"角色不存在"与"跨产品访问"两种响应,全部走统一 404 "角色不存在"。 // 旧实现先 FindOne 再判 ProductCode 会形成枚举 oracle: // - req.Id 不存在 → 404 // - req.Id 存在但在别的产品 → 403 // 攻击者遍历 id 即可画出跨产品 roleId 分布图。新实现: // (1) 先 FindOne 看 id 是否在 DB 里存在; // (2) 非超管且 ProductCode 不匹配时统一伪装成"不存在",与真正的 NotFound 响应体一致, // 消除存在性差异;超管仍可跨产品查看。 role, err := l.svcCtx.SysRoleModel.FindOne(l.ctx, req.Id) if err != nil { return nil, response.ErrNotFound("角色不存在") } if !caller.IsSuperAdmin && caller.ProductCode != role.ProductCode { return nil, response.ErrNotFound("角色不存在") } permIds, err := l.svcCtx.SysRolePermModel.FindPermIdsByRoleId(l.ctx, role.Id) if err != nil { return nil, err } return &types.RoleItem{ Id: role.Id, ProductCode: role.ProductCode, Name: role.Name, Remark: role.Remark, Status: role.Status, PermsLevel: role.PermsLevel, PermIds: permIds, CreateTime: role.CreateTime, }, nil }