Kapitola 06 / 09
ENSK

SmartExchange · .NET 10 · Chapter 06

PlanResources → AST → SQL

Spoločný klient vráti neutrálny query plan. SQL adapter preloží iba podporované výrazy a známe mapovania; Cerbos nevracia vykonateľné SQL.

Shared code · Intaker + Web APIReviewed · 2026-10-27

Transport a neutrálne kontrakty

Trieda / metódaImplementovaná zodpovednosť
CerbosAuthorizationPolicyClient.PlanResourcesAsync()Premení principal/resource atribúty na Protobuf, odošle jednu action cez gRPC, vyžiada metadata a prenesie deadline/cancellation. Klient/channel sa používa počas života aplikácie; pri ukončení sa uvoľní.
CerbosQueryPlanMapper.Map(response, request)Overí validation errors a zhodu request/resource/action. Vytvorí AuthorizationQueryPlan so zachovaním DecisionId.
AuthorizationQueryPlanKind, ResourceKind, Action, RequestId, DecisionId, voliteľný Filter.
Expression recordsAuthorizationAttribute, AuthorizationConstant, AuthorizationOperation, AuthorizationCollectionExists.

Mapper podporuje and, or, eq, in, konštantné zoznamy a jednopremenný exists/lambda nad resource kolekciou. Je to zámerne obmedzený preklad, nie celé CEL. Nepodporovaná forma vyvolá chybu; autorizácia sa potichu nepreskočí.

Spoločná SQL hranica

Interface and factory · signatures condensed
// BmcGroup.Authorization.SqlKata
Query IAuthorizationQueryAdapter.Apply(
    Query query, AuthorizationQueryPlan plan, AuthorizationSqlMapping mapping);

AuthorizationSqlMapping AuthorizationSqlMappingFactory.Create(
    string resourceKind, string action, AuthorizationSqlAttribute resourceId,
    IEnumerable<AuthorizationRelationship> relationships);

AuthorizationSqlMapping spája resource/action, skalárne atribúty a vzťahy. AuthorizationSqlAttribute dodá dôveryhodný stĺpec a typ hodnoty; AuthorizationSqlRelationship dodá element column a novú korelovanú query cez CreateQuery.

Plan kindSqlKataAuthorizationQueryAdapter.Apply()
AlwaysAllowedPonechá business query.
AlwaysDeniedPridá 1 = 0. Intaker ho odmietne už skôr.
ConditionalZostaví samostatný predikát a pridá ho cez AND.

Adapter kontroluje zhodu resource/action, typy konštánt a mapované identifikátory. Aktuálne limity zahŕňajú hĺbku 32 a najviac 1 800 autorizačných parametrov. Odmietnutý plán musí operáciu ukončiť.

Oba exporty cez rovnaký AST a SQL adapter

PlanResourcesAsync() → CerbosQueryPlanMapper.Map() → AuthorizationCollectionExists → AuthorizationSqlMappingFactory.Create() → SqlKataAuthorizationQueryAdapter.Apply().

Person/export

resource.attr.companyIds → AuthorizationCollectionExists → EXISTS PersonInCompany JOIN Company.

PlanResources request · JSON
PlanResources request · JSON
{
  "requestId": "presentation-person-export",
  "actions": [
    "export"
  ],
  "includeMeta": true,
  "principal": {
    "id": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
    "roles": [
      "user"
    ],
    "attr": {
      "product": "QA",
      "grants": [
        {
          "assignmentId": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb",
          "resourceId": "11111111-1111-1111-1111-111111111111",
          "resource": "Company",
          "action": "read",
          "scope": "Resource",
          "isPublic": false
        }
      ]
    }
  },
  "resource": {
    "kind": "Person",
    "policyVersion": "presentation-demo",
    "attr": {}
  }
}
Očakávaný plan tvar · ilustračný JSON, nezachytený
Očakávaný plan tvar · ilustračný JSON, nezachytený
{
  "requestId": "presentation-person-export",
  "actions": [
    "export"
  ],
  "resourceKind": "Person",
  "policyVersion": "presentation-demo",
  "filter": {
    "kind": "KIND_CONDITIONAL",
    "condition": {
      "expression": {
        "operator": "exists",
        "operands": [
          {
            "variable": "request.resource.attr.companyIds"
          },
          {
            "expression": {
              "operator": "lambda",
              "operands": [
                {
                  "expression": {
                    "operator": "eq",
                    "operands": [
                      {
                        "variable": "relatedId"
                      },
                      {
                        "value": "11111111-1111-1111-1111-111111111111"
                      }
                    ]
                  }
                },
                {
                  "variable": "relatedId"
                }
              ]
            }
          }
        ]
      }
    }
  }
}
SQL · ekvivalentný tvar query
SQL · ekvivalentný tvar query
-- Synthetic Person/Company demonstration; equivalent SQL, not a captured query.
-- Read-only example. No policy or ACL assignments are changed.
DECLARE @companyId uniqueidentifier = '11111111-1111-1111-1111-111111111111';

SELECT [Person].*
FROM dbo.Person AS [Person]
WHERE [Person].[Deleted] = 0
  AND EXISTS (
      SELECT 1
      FROM dbo.PersonInCompany AS acl_relation_0_0
      INNER JOIN dbo.Company AS acl_relation_0_1
        ON acl_relation_0_1.Id = acl_relation_0_0.CompanyId
       AND acl_relation_0_1.Deleted = 0
      WHERE acl_relation_0_0.PersonId = [Person].Id
        AND acl_relation_0_0.Deleted = 0
        AND acl_relation_0_1.Id = @companyId
  );

-- Production code binds @companyId as a GUID through SqlKata.
-- Its actual parameter names may differ. Keep template/instance filters.
-- Authorization is applied before paging/counts and before returning data.

Request · Expected plan · SQL

InterestedParty/export

resource.attr.projectIds → AuthorizationCollectionExists → EXISTS Project.

PlanResources request · JSON
PlanResources request · JSON
{
  "requestId": "presentation-interested-party-export",
  "principal": {
    "id": "5a3e5b0f-fb6d-4abf-ba4f-8b581365a795",
    "roles": [
      "user"
    ],
    "attr": {
      "product": "API_Dev1",
      "grants": [
        {
          "assignmentId": "a7f53aab-6f40-4204-b1d3-02ea54f1713e",
          "resourceId": "b48e464a-88cf-4743-bbce-98d6ba89e399",
          "resource": "InterestedParty",
          "action": "read",
          "scope": "Project",
          "isPublic": false
        }
      ]
    }
  },
  "resource": {
    "kind": "InterestedParty",
    "policyVersion": "presentation-demo",
    "attr": {}
  },
  "actions": [
    "export"
  ],
  "includeMeta": true
}
Očakávaný plan tvar · ilustračný JSON, nezachytený
Očakávaný plan tvar · ilustračný JSON, nezachytený
{
  "requestId": "presentation-interested-party-export",
  "actions": [
    "export"
  ],
  "resourceKind": "InterestedParty",
  "policyVersion": "presentation-demo",
  "filter": {
    "kind": "KIND_CONDITIONAL",
    "condition": {
      "expression": {
        "operator": "exists",
        "operands": [
          {
            "variable": "request.resource.attr.projectIds"
          },
          {
            "expression": {
              "operator": "lambda",
              "operands": [
                {
                  "expression": {
                    "operator": "eq",
                    "operands": [
                      {
                        "variable": "projectId"
                      },
                      {
                        "value": "b48e464a-88cf-4743-bbce-98d6ba89e399"
                      }
                    ]
                  }
                },
                {
                  "variable": "projectId"
                }
              ]
            }
          }
        ]
      }
    }
  }
}
SQL · ekvivalentný tvar query
SQL · ekvivalentný tvar query
-- Proposed InterestedParty/export Project-scope example; equivalent SQL, not captured runtime output.
-- Illustration, not captured runtime output. Bind @ProjectId from the approved plan.
-- Every schema/table/column mapping comes from trusted application metadata.
DECLARE @ProjectId uniqueidentifier = 'b48e464a-88cf-4743-bbce-98d6ba89e399';

SELECT ip.Id
FROM dbo.InterestedParty AS ip
WHERE ip.Deleted = 0
  AND EXISTS (
      SELECT 1
      FROM dbo.Project AS acl_project
      WHERE acl_project.Id = ip.ProjectId
        AND acl_project.Deleted = 0
        AND acl_project.Id = @ProjectId
  );
-- Ordinary business filters are ANDed with this predicate.
-- Apply authorization before COUNT, ORDER BY/OFFSET and export materialization.
-- No user-supplied ProjectId filter is required to activate this authorization.

Request · Expected plan · SQL

Oba dokumentačné requests používajú presentation-demo/export a ponechajú relationship atribúty záznamov neznáme. Oba očakávané JSON príklady ukazujú celý EXISTS/lambda predikát pre jedno vyhovujúce ID; sú ilustračné, nepochádzajú zo živého volania. Aj SQL je ekvivalentný tvar, nie zachytený výstup vykonania.

Korelované EXISTS nenásobí root riadky. Deleted=0 platí pre každý relationship krok aj root business query. Autorizačný predikát sa aplikuje pred count/paging/načítaním výsledkov.

Samostatné runtime overenie: skutočný InterestedParty/read JSON AST.