package handler import ( "context" "net/http" "strings" "bj_power_mes/common/httpx" "bj_power_mes/internal/svc" ) // pathPermMap 请求方法+路径 → 所需按钮级权限码(块2:后端接口兜底校验)。 // 路径中的 :id 统一以 * 结尾匹配。 var pathPermMap = map[string]string{ "POST:/api/v1/product-types": "produce.product:add", "PUT:/api/v1/product-types": "produce.product:edit", "DELETE:/api/v1/product-types/*": "produce.product:delete", "POST:/api/v1/work-orders": "produce.workorder:add", "PUT:/api/v1/work-orders": "produce.workorder:edit", "DELETE:/api/v1/work-orders/*": "produce.workorder:delete", "POST:/api/v1/daily-plans": "produce.workorder:dailyplan", "PUT:/api/v1/bom": "produce.bom:edit", "POST:/api/v1/material-requests/generate": "produce.material:generate", "POST:/api/v1/plc/send-process": "produce.plc:send", "POST:/api/v1/process-flows": "produce.processflow:add", "DELETE:/api/v1/process-flows/*": "produce.processflow:delete", "POST:/api/v1/process-flows/upload": "produce.processflow:upload", "POST:/api/v1/process-steps": "produce.processflow:edit", "POST:/api/v1/stations": "produce.station:edit", "POST:/api/v1/users": "sys.rbac:user", "PUT:/api/v1/users": "sys.rbac:user", "DELETE:/api/v1/users/*": "sys.rbac:user", "POST:/api/v1/roles": "sys.rbac:role", "PUT:/api/v1/roles": "sys.rbac:role", "DELETE:/api/v1/roles/*": "sys.rbac:role", "POST:/api/v1/permissions": "sys.rbac:perm", "PUT:/api/v1/permissions": "sys.rbac:perm", "DELETE:/api/v1/permissions/*": "sys.rbac:perm", } // userHasPerm 校验当前登录用户是否拥有某权限码(SUPER_ADMIN 或 * 放行)。 // 用户ID 使用 uidFromRequest:优先取 context,缺失时回退解析 Authorization token。 func userHasPerm(r *http.Request, svcCtx *svc.ServiceContext, code string) bool { if code == "" { return true } userId := uidFromRequest(r, svcCtx) if userId <= 0 { return false } usr, err := svcCtx.EntClient.User.Get(r.Context(), userId) if err != nil { return false } role, err := svcCtx.EntClient.Role.Get(r.Context(), usr.RoleId) if err != nil { return false } if role.Code == "SUPER_ADMIN" { return true } for _, c := range role.PermissionCodes { if c == "*" || c == code { return true } } return false } // permissionGuard 按钮级权限后端兜底中间件(仅对写操作映射表内的路径生效) func permissionGuard(svcCtx *svc.ServiceContext) func(http.HandlerFunc) http.HandlerFunc { return func(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { code, ok := pathPerm(r.Method, r.URL.Path) if ok && !userHasPerm(r, svcCtx, code) { httpx.FailHTTP(w, http.StatusForbidden, "无操作权限:"+code) return } next(w, r) } } } // pathPerm 先按完整路径精确匹配;未命中时把末段替换为 * 再匹配(用于 :id 结尾的路径)。 func pathPerm(method, path string) (string, bool) { key := method + ":" + strings.TrimSuffix(path, "/") if code, ok := pathPermMap[key]; ok { return code, true } segs := strings.Split(key, "/") if len(segs) > 0 { segs[len(segs)-1] = "*" } code, ok := pathPermMap[strings.Join(segs, "/")] return code, ok }