Tischsicherheit

Power Portals Pro sichert Daten auf drei Ebenen: Welche Tabellen ein Benutzer berühren kann, welche Spalten dieser Tabellen er sehen und ändern kann, und welche Zeilen überhaupt zurückkommen. Alle drei werden in einer Registrierung pro Tabelle festgelegt. Beschreiben Sie diese Registrierung mit AddTableAccess — es ist der Weg, eine Tabelle zu erteilen, und was die Projektvorlagen für jede Tabelle verwenden, die sie registrieren. Wenn eine Regel nicht beschreibbar ist, können dieselben drei Antworten stattdessen als Klasse ITablePermissionProvider geschrieben werden; beide erzeugen dasselbe und setzen sich auf dieselbe Weise zusammen. Nichts wird gewährt, bis eine von ihnen dies sagt: Eine Tabelle, die keine Registrierung abdeckt, ist unerreichbar, was der fehlerschließende Standard ist.

Tipp

Sie müssen dies nicht von einer leeren Seite schreiben. Generierte Projekte liefern eine secure-a-table Fähigkeit: Bitten Sie Ihren Codieragenten, eine Tabelle zu sichern, und es arbeitet sich durch, welche Tabelle, für wen sie ist, für welche Zeilen, welche Operationen und welche Spalten, dann schreibt er die Registrierung und führt die entsprechenden Änderungen in Dataverse über den Power Portals Pro MCP-Server vor – erstellt die Portalrolle, wenn der Zugriff rollengebunden ist, und gewährt dem Anwendungsbenutzer die Privilegien, die die Antworten implizieren. Anschließend meldet jede Tabelle check_setup , an die Ihre Seiten binden, für die nichts Zugriff gewährt, sowie jede Registrierung, die die Spaltensicherheit abhebt. Siehe Starten → MCP-Server.

Alle, oder nur einige Leute

Jede Registrierung gibt an, für wen sie ist, und es gibt zwei Antworten. Registrieren Sie sie im Portal, und sie gilt für ein Publikum, das Ihre Codenamen nennen – alle oder jeden angemeldeten Nutzer. Registrieren Sie sie darin AddPortalRole , und sie gilt für die Inhaber dieser Rolle, was eine Datenentscheidung ist, die ein Administrator in Dataverse trifft. Der Zugriff selbst wird in beiden Fällen gleich beschrieben.

Registrierung Gilt für Um zu ändern, wer es bekommt.
AddTableAccess("account", t => t.ForSignedInUsers()…) jeden, den das Publikum abdeckt, auf jede Anfrage Code bearbeiten und neu deployen
AddPortalRole("Credit Manager", role => role.WithTableAccess("account", …)) Kontakte, die diese Portal-Rolle innehaben, und sonst niemand. die Rolle in Dataverse zuweisen oder entziehen – keine Bereitstellung

Eine Tabelle kann einmal für jede portalweite Zielgruppe registriert werden – ForEveryone() für das, was jeder erreichen kann, für das, ForSignedInUsers() was das Anmelden hinzufügt – und die beiden summieren sich. Ein Besucher bekommt die erste; ein angemeldeter Nutzer bekommt beide, wobei jede Operation auf die Zeilen der Registrierung beschränkt ist, die sie gewährt. Mit den beiden untenstehenden Registrierungen liest jeder jeden Artikel, und ein angemeldeter Autor kann ebenfalls einen schreiben und seinen eigenen bearbeiten:

Rollen addieren; sie ziehen niemals ab. Der Zugriff eines Nutzers sind die portalweiten Registrierungen plus jede Rolle, die er innehat, vereint – also ist die portalweite die Etage, auf der alle stehen, und eine Rolle kann sie nur erhöhen. Eine Rolle kann eine Spalte oder Zeile nicht zurücknehmen, die die portalweite Registrierung gewährt hat; um den meisten Leuten etwas vorzuenthalten, gewähre es in einer Rolle statt portalweit. (Setzt SecurityOptions.Roles.CompositionBehavior stattdessen auf Restrictive "wenn alle Gruppen zustimmen.)

Also: Wenn jeder Nutzer dieser Art Zugang haben sollte, registrieren Sie es gegen das Portal. Wenn nur einige – und welche Person eine Frage ist, deren Antwort ohne Freigabe geändert wird – sie in eine Rolle einordnen. Eine Rollenregistrierung gewährt nichts, bis jemand einen Portal-Rolleneintrag mit diesem Namen erstellt und zuweist, weshalb man in einem neuen Projekt unschädlich sitzen kann.

Beschreibung des Zugangs zu einem Tisch

Die meisten Tabellen wollen dieselben wenigen Regeln: Für wen die Tabelle gedacht ist, welche ihrer Zeilen sie erreichen, was sie tun dürfen und welche Spalten sie sehen. Alle AddTableAccess vier in einer Registrierung stehen und erzeugen eine gewöhnliche ITablePermissionProvider Meldung – nichts weiter nachgelagert weiß den Unterschied. Was es kauft, ist, dass die drei Entscheidungen, die sich einigen müssen (der Filter, die Erstellen und die beschreibbaren Spalten), einmal statt dreimal getroffen werden.

Ein Publikum, ein Zeilenumfang und Allow(…) alles sind erforderlich. Keines davon hat einen Standard, denn jeder plausible Standard ist eine Möglichkeit, Daten zu veröffentlichen, indem man etwas weglässt – und eine Registrierung, die einen Fehler macht, scheitert beim Start und nicht in der Produktion.

Reihenteleskope

Der Scope filtert jede Abfrage für die Tabelle – Raster, Lookups, Subgrids, Diagramme und den Abruf vor einem Speicher- oder Löschen. Die benannten Scopes decken die Formen ab, die Portale ständig benötigen:

Welche Reihen Umfang Auf Create
Jede Reihe AllRows() Nichts festgesetzt
Die eigenen Datensätze des Nutzers RowsOwnedByContact("customerid") Der Lookup ist auf sie eingestellt
Die Unterlagen ihrer Kollegen, auf demselben Konto RowsOfTheirAccount("customerid") Die Suche ist auf ihr Konto eingestellt
Aufzeichnungen, die an einem Elternteil hängen, die sie erreichen können RowsViaParent("salesorderid", "salesorder", p => …) Nichts festgelegt – der eigene Zugang der Eltern entscheidet
Aufzeichnungen, die auf mehr als eine Weise auf sie hinweisen RowsMatchingAny(r => r.RowsOwnedByContact("customerid"), r => r.RowsOfTheirAccount("customerid")) Was der erste Eigentumsbereich auflistete Sets
Ihre eigene Kontaktreihe OwnRecordOnly() Kein Erstellen

Die Eigentumsbereiche legen die Spalte selbst fest, wenn ein Datensatz erstellt wird, nach den Berechtigungsprüfungen: Der Benutzer benötigt keinen Schreibzugriff darauf und kein Append To auf der Tabelle, auf die er zeigt, der Wert stammt aus der Sitzung und nicht aus der Anfrage, und ein späterer Speicher, der ihn ändern würde, wird abgelehnt. Das ist es, was einen Datensatz, den jemand erstellt, im Filter speichert, dem er unterliegt. Verwenden OwnedBy('column') Sie, wenn die besitzende Spalte nicht diejenige ist, nach der die Zeilen gefiltert sind, und WithoutStamping() wenn ein Plugin sie bereits setzt.

Beim Lesen und Ändern unterscheiden sich

One Scope beantwortet jede Operation, es sei denn, du sagst etwas anderes. RowsForWriting schränkt die Zeilen ein, die ein Benutzer ändern kann, ohne die Zeilen einzugrenzen – "Jeder liest jeden Kontakt, jeder bearbeitet nur seine eigene" ist diese Unterscheidung und nichts anderes – und RowsForDeleting schränkt das Zerstören noch weiter ein, weil die Erlaubnis, einen Datensatz zu korrigieren, nicht dasselbe ist wie ihn zu vernichten. Jeder fällt auf die darüberliegende zurück, sodass eine Registrierung, die keinen Unterschied macht, keine zieht. Erstellt bleiben unbeeinträchtigt: Es gibt noch keine Zeile zum Filtern.

Wenn die benannten Zielfernrohre nicht passen

RowsMatching nimmt einen eigenen Filter, ohne die Registrierung zu verlassen. Gib ihm FetchXML – ein <filter> Element oder ein Ganze, <fetch> dessen Filter und Joins kopiert werden, mit {currentUserId} für den angemeldeten Kontakt – oder einen Callback, der pro Anfrage ausgeführt wird und entweder das FetchXML zurückgibt, das aus der Antwort deiner Dienste zusammengesetzt ist, oder einen Filter, den er gebaut hat. Beides erhält dasselbe TableQueryContext wie ein Anbieter, sodass er weiß, wer fragt und ob die Zeilen gelesen, aktualisiert oder gelöscht werden. Nichts zurückzugeben gewährt keine Zeilen: TableQueryFilter.AllRows so sagt man jede Zeile.

Beschreibung des Zugangs zu einer Rolle

Innerhalb AddPortalRole der Rolle befindet sich das Publikum, also nennt die Registrierung keine anderen. Rollen addieren und ziehen niemals ab: Der Zugriff eines Nutzers sind die portalweiten Registrierungen plus jede Rolle, die er innehat, gewerkschaftlich organisiert. Die Portalrollen selbst – was sie sind, wie sie zugewiesen werden und wie sie zusammengesetzt sind – sind der nächste Abschnitt.

Anmerkung

Eine Anbieterklasse bleibt der Weg, alles auszudrücken, was eine Beschreibung nicht ausdrücken kann, und sie setzt sich identisch zusammen – AddTablePermissionProvider<T> und WithPermissions<T> bleibt unverändert. Die generierten Projekte liefern keine weitere aus: Jede Tabelle, die sie registriert, wird beschrieben, einschließlich contact der Rolle des Kreditmanagers.

Portalrollen

Eine Portalrolle ist die bevorzugte Möglichkeit, ein Portal zu sichern. Sie bindet Berechtigungsanbieter an einen Namen, den Administratoren Kontakte in Dataverse zuweisen, sodass die Anbieter nur für die Personen gelten, die diese Rolle innehaben – und wer sie innehat, ist Daten, kein Code. Ein direkt Program.cs registrierter Anbieter gilt im Vergleich für jeden Nutzer.

Die Aufteilung ist absichtlich. Dataverse besitzt die Namen und die Zuweisungen, die ein Administrator in der modellgesteuerten App verwaltet. Dein Code besitzt, was jeder Name bedeutet. Das Gewähren oder Widerrufen des Zugriffs ist dann eine Datenänderung: kein Rebuild, kein Redeploy.

1. Erstelle die Rolle und verweise sie

Erstelle einen Portal-Rolleneintrag und weise ihn den Kontakten zu, die ihn haben sollten. Der Rolleneintrag enthält nichts außer einem Namen und einer Beschreibung – in Dataverse existieren keine Berechtigungsdaten.

2. Die Rolle an ihre Anbieter zu binden

Gleiche den Namen des Rollendatensatzes ab und liste auf, was er vergibt. Die Anbieter sind für dich registriert, also registrierst du sie nicht selbst.

Dieser letzte Punkt ist wichtig: Registrieren Sie niemals auch den Anbieter einer Rolle bei AddTablePermissionProvider<T>(). Das legt sie in die globale Menge und gewährt sie allen, wodurch die Rolle stillschweigend verworfen wird. Reservieren AddTablePermissionProvider<T>() Sie Regeln für Regeln, die wirklich für jeden Nutzer gelten.

Wie sich Rollen kombinieren

Die Berechtigungen eines Nutzers stammen von den global registrierten Anbietern plus jeder Rolle, die er innehat, und diese Gruppen fügen sich wie folgt zusammen:

Tipp

Bei additiver Komposition verneint nichts – etwas bleibt nur geschlossen, solange keine Gruppe es öffnet. Ein global registrierter Anbieter ist die richtige Heimat für eine Regel, die für jeden Nutzer gilt, weil sie immer im Fold ist, aber kein Veto: Eine Rolle, die die Operation gewährt oder die Spalte benennt, öffnet sie wieder. Um etwas geschlossen zu halten, welche Rollen ein Nutzer auch immer innehat, gewähren Sie es in keiner Rolle – oder setzen SecurityOptions.Roles.CompositionBehavior Sie auf Restrictive, wo jede Gruppe zustimmen muss.

Rollen in Seiten und Navigation

Rollennamen gelangen als Standard-ASP.NET Rollenbehauptungen in den Browser, sodass Seitenautorisierung und bedingte Benutzeroberfläche ohne zusätzliche Funktionen funktionieren:

Der React-Stack liest dieselben Namen aus auth.user.rolesund <AuthorizedView roles="Dealer"> sperrt Inhalte auf die gleiche Weise. Interne (Systembenutzer-)Anmeldungen tragen stattdessen ihre Dataverse-Sicherheitsrollennamen hierher, sodass eine Überprüfung beide Arten von Benutzern abdeckt.

Genehmigung für die richtige Art von Rolle

Eine Portalrolle und eine Dataverse-Sicherheitsrolle können einen Namen teilen und [Authorize(Roles = "…")] können sie nicht voneinander unterscheiden – das entspricht der Untyped-Rollenbehauptung, die beide trägt. Zwei Attribute stellen die engere Frage:

Rollennamen werden wortwörtlich angegeben: Kommas, Kolon und Anführungszeichen sind alle in Ordnung, weil der Name nie aus einer Liste herausgeschnitten wird. Das Stapeln zweier Attribute erfordert beide, wie es gestapelte [Authorize] Attribute immer getan haben; die Auflistung zweier Namen in einem Attribut erfordert beides. Der gleiche Check ist im Code User.IsInPortalRole("Dealer") als und User.IsInSecurityRole("Sales Manager")verfügbar.

Die gleiche Unterscheidung im Blazor-Markup. <AuthorizeView Roles="…"> liest die untypisierte Rollenbehauptung und trägt daher dieselbe Mehrdeutigkeit wie das einfache Attribut; <PortalRoleView> fragt nach einer Art. Gib / PortalRole SecurityRole für einen einzelnen Namen oder PortalRoles / SecurityRoles für mehrere – eine Sammlung statt eines kommagetrennten Strings, da Dataverse-Namen routinemäßig Kommas enthalten:

React nimmt <AuthorizedView> dieselben zwei Gates, neben dem bestehenden roles . Mehrere Namen in einem Gate anzugeben bedeutet jeden von ihnen; zwei Gates zu liefern bedeutet beide. Die dahinterstehenden Prädikate — hasPortalRole, hasSecurityRole, — hasRole werden für imperative Prüfungen exportiert:

Best Practice – an der Quelle filtern

Greifen Sie zu diesen, wann immer das zu schützende Objekt wirklich administrativ ist. Eine Portalrolle zu erstellen ist bewusst niedriger, als eine Dataverse-Sicherheitsrolle zu erhalten, daher erlaubt eine Kontrolle, die beide akzeptiert, einem Administrator Zugang zu der geschützten Dataverse-Rolle zu gewähren, indem er einfach eine Portalrolle nach ihr benannt.

Anmerkung

Rollen sind nicht kostenlos. Jede Rolle, die ein Nutzer hält, wird zweimal in das Auth-Cookie geschrieben – einmal als Standard-Rollenbehauptung, also [Authorize(Roles)] funktioniert, und einmal als die artspezifische Behauptung, die die oben genannten Überprüfungen möglich macht – was etwa 160 Bytes pro Rolle beträgt. Etwa fünfzehn Rollen pro Nutzer passen immer noch in einen einzigen Cookie; darüber hinaus teilt sich der Cookie in Chunks, und das Erste, was nachgibt, ist meist das Header-Limit eines Reverse-Proxys, das eine undurchsichtige 400 angibt, anstatt dass Rollen erwähnt werden. Bevorzuge einige breite Rollen gegenüber vielen engen.

Neuen Nutzern eine Startrolle geben

Nenne die Rollen, mit denen jedes neue Konto beginnen sollte, und die Rolle, die für ausgeloggte Besucher gilt:

Oder entscheide es in Dataverse, ohne eine Veröffentlichung. Die Portal-Rollenkonfigurationstabelle koppelt eine Rolle mit einem Zuweisungsmodus, und ein Administrator kann ändern, wer was aus der modellgesteuerten App erhält:

Wenn die Rollen von der Person abhängen – deren E-Mail-Domain, der Anbieter, bei dem er sich angemeldet hat, eine Einladung – registrieren Sie sich IPortalRoleAssignmentProvider stattdessen. Jeder registrierte Anbieter wird konsultiert, sodass Ihr Provider zur konfigurierten Liste hinzugefügt wird, anstatt sie zu ersetzen. So oder so wird die Zuweisung einmal durchgeführt, wenn das Konto erstellt wird; sie wird beim Anmelden nie erneut angewendet, sodass eine Rolle, die ein Administrator entfernt, entfernt bleibt.

Anmerkung

Ein Nutzer nimmt eine neu zugewiesene Rolle durch Ab- und Wiedereinloggen auf – das Anmelden liest seine Rollen erneut. Rollenzuweisungen werden ansonsten pro Benutzer für 24 Stunden zwischengespeichert, um also eine Änderung auf jemanden anzuwenden, der bereits angemeldet ist, den Portal-Rollen-Cache im Standortverwaltungsbereich zu löschen: Ihre Sitzung erkennt ihn bei der nächsten Aktualisierung innerhalb von zehn Minuten wieder auf, und eine entfernte Rolle funktioniert dann nicht mehr, sobald eine hinzugefügte startet. Die Portal-Rollen-Konfigurationstabelle wird für fünfzehn Minuten separat zwischengespeichert, sodass eine dort hinzugefügte Zeile die nächste Registrierung von selbst erreicht – löschen Sie den "PortalRoleConfiguration"-Cache, um sie sofort zu ermöglichen. Das Deaktivieren einer Konfigurationszeile verhindert, dass sie ihre Rolle vergibt, genauso wie das Deaktivieren einer Rolle sie widerruft.

Stattdessen einen Anbieter schreiben

Greifen Sie zu einer Klasse, wenn eine Beschreibung nicht sagen kann, was Sie meinen – eine Regel, die von etwas abhängt, das nur Ihr Code kennt, oder eine, die den Datensatz während des Flugs überprüfen muss. ITablePermissionProvider Ist in jedem Fall das, was jede Registrierung wird: Ein Anbieter steuert eine Tabelle, beantwortet, was ein Nutzer damit machen darf, welche seiner Spalten er lesen und schreiben darf, und – über den untenstehenden Abfragefilter – welche seiner Zeilen er überhaupt sehen kann. Eine beschriebene und eine geschriebene Registrierung bilden identisch, sodass ein Portal beide verwenden kann, und eine Tabelle kann von der einen gewährt und von der anderen erweitert werden.

Die Schnittstelle hat ein erforderliches Mitglied. GetPermissionsAsync Erhält ein UserInfo Formular, das die ID des Benutzers, seine Portalrollen und seine Dataverse-Sicherheitsrollen enthält, und liefert eine TablePermissions Beschreibung, die alles beschreibt, was der Nutzer erhält:

Registrierung eines Anbieters

Ein auf diese Weise registrierter Anbieter gilt für jeden Nutzer, ob angemeldet oder nicht:

Das ist auch die einzige Möglichkeit, allen etwas wegzunehmen: Rollen setzen standardmäßig additiv zusammen, sodass eine Rolle Zugriff hinzufügen, aber nie entfernen kann. Portalweite Einschränkungen gehören zu einem global registrierten Anbieter, der immer Teil des Pakets ist.

Betrieb

TablePermissions.Operationsist ein TableSecurityPermission Flaggenwert — Read, , Create, WriteDelete, und Append AppendTo. Zwei Dinge sind darüber bekannt:

Anmerkung

Es gibt absichtlich keinen "Inspiziere jede Zeile nach dem Laden"-Hook. So zu filtern zerstört das Ausgreifen – eine Seite mit 50 bringt weniger zurück – ergibt die Gesamtzählung falsch und bezahlt Dataverse, um Zeilen abzurufen, die es dann wegwirft. Das Scoping der Abfrage hält stattdessen das Ausziehen und zählt durch Konstruktion korrekt.

Best Practice – an der Quelle filtern

Daten in der Abfrage scopen, nicht danach. Das Framework bietet absichtlich keinen Hook, der jede Zeile überprüft, sobald sie abgerufen wurde: Das Filtern auf diese Weise unterbricht die Ausrichtung (eine Seite mit 50 kommt zu kurz an), macht die Gesamtzählung falsch und bezahlt Dataverse dafür, Zeilen abzurufen und dann zu verwerfen. GetQueryFilterAsync Fügt die Bedingungen vor der Abfrage hinzu, sodass Paging- und Zählzahlen durch die Konstruktion korrekt bleiben und die Zeilen, die ein Benutzer möglicherweise nicht sieht, überhaupt nicht abgerufen werden.

Sicherheit auf Reihenebene

GetQueryFilterAsync gibt einen Filter zurück, den das Framework der Abfrage hinzugefügt hat, bevor Dataverse ihn ausführt, sodass Zeilen, die der Benutzer möglicherweise nicht sieht, nie abgerufen werden. Er gilt für jede Abfrage, die das Portal für die Tabelle ausstellt – Raster, Nachschlage, Subgrids, Diagramme und Einzeldatensatz-Loads – und läuft unter beiden Sicherheitsmodellen, sodass er auch dort gilt, wo Dataverse-native Sicherheit das Operationsgate umgeht.

Baue den Filter mit context.CreateFilter() und gib ihn zurück; zurückgeben null bedeutet keine Zeilenbeschränkung. Der Kontext trägt den aktuellen Benutzer als , EntityReferencedie Rollen, die er innehat, und wofür die Zeilen gleich verwendet werden sollen. Bedingungen werden über dieselbe FetchXMLBuilder API hinzugefügt, wie überall sonst: FetchXMLBuilder

Dieser Anbieter gewährt drei Spalten und contact beschränkt jede Kontaktanfrage auf den eigenen Datensatz des angemeldeten Nutzers:

Lesen, aktualisieren und löschen

TableQueryContext.Operation erklärt, warum die Reihen abgerufen werden, damit ein Anbieter sie für jede unterschiedlich bewerten kann:

Wie mehrere Filter kombiniert werden

Eine Tabelle kann mehr als einen Anbieter haben – einen global registrierten plus einen aus jeder Rolle, die der Nutzer innehat. Das Framework entscheidet, wie sich ihre Filter kombinieren, sodass ein Anbieter nie wissen muss, was die anderen gemacht haben:

Anmerkung

Zeilen versagen geschlossen, wie Spalten: Ein Provider, der zurückgibt null – oder ein Filter ohne Bedingungen – gewährt keine Zeilen, und innerhalb einer Gruppe leert er die Gruppe. Jede Zeile muss mit TableQueryFilter.AllRowsabgefragt werden. Dort liegt die eine Asymmetrie: Die Vereinigung jeder Zeile mit irgendetwas ist jede Zeile, also wenn eine Gruppe, die der Tabelle Antworten AllRowsgibt, kommt die Tabelle ungefiltert zurück, egal wie sorgfältig die anderen Rollen sie begrenzt haben. Das bedeutet additive Komposition, aber es ist die einzige Möglichkeit, wie der Filter einer Rolle so aussehen kann, als würde er ignoriert.

Filtern durch eine verwandte Tabelle

AddLink fügt eine Tabelle ein, damit der Filter seine Spalten testen kann. Setzen Sie den Test im Filter statt auf den Link – Bedingungen im Filter funktionieren weiterhin, wenn das Framework das Join nach außen lockert, und Bedingungen im Link würden nicht:

Anmerkung

Der obige Join reicht bis zu vielen Zeilen, sodass Dataverse das Konto einmal pro Mitgliedschaft zurückgibt – ein Raster mit wiederholten Zeilen und eine Gesamtsumme, die sie zählt. Das Framework erkennt diese Form und markiert die Abfrage distinct, projiziert den Primärschlüssel der Tabelle, sodass die Deduplizierung nur die Zeilen entfernen kann, die der hinzugefügte Join hinzugefügt hat. Ein Join, der stattdessen nach oben geht und mit dem eigenen Primärschlüssel der zugehörigen Tabelle verbunden ist, entspricht höchstens einer Zeile und bleibt genau so, wie er war. So oder so schreibst du den Filter und sonst nichts – aber es ist wichtig zu wissen, dass ein Join nicht kostenlos ist und dass eine Regel, die du als flache Bedingungen in den eigenen Spalten der Tabelle ausdrücken kannst, die günstigere Form ist.

Tipp

Wenn eine Tabelle pro Rolle einen anderen Umfang benötigt, kannst du immer noch einen Anbieter schreiben und darauf context.User.PortalRoles verzweigen – aber das musst du nicht mehr. Zwei Rollen können jeweils ihren eigenen Anbieter haben und das Framework vereint ihre Filter für dich.

Wer besitzt einen neuen Rekord

Ein Zeilenfilter steuert Scopes, Reads, Updates und Löschungen, aber ein Create hat keine Zeile zum Filtern. Eine Tabelle, die auf "Zeilen, die ich besitze" beschränkt ist, würde es einem Benutzer immer noch erlauben, eine Zeile zu erstellen, die jemand anderem gehört – oder niemandem gehört, die der Ersteller dann nicht sehen kann. Deklariere die Spalte, in der steht, wem ein Datensatz gehört, und das Framework setzt sie:

Koppele es mit einem Zeilenfilter in derselben Spalte, sodass die Datensätze, die ein Benutzer erstellt, die einsehen können. Für Eigentum, das nicht nur der erstellende Kontakt ist – zum Beispiel das Konto des Erstellers – implementiere ITableRecordOwnershipProvider und registriere es bei AddTableRecordOwnershipProvider<T>(). Setze keinen Besitzer in ein: ITableRecordInterceptor Interceptoren laufen vor den Berechtigungsprüfungen, sodass das, was sie setzen, als eigener Schreib des Nutzers bewertet wird.

Das Framework ruft es bei jeder Erstellung dieser Tabelle nach den Berechtigungsprüfungen auf und setzt jede Spalte Columns in das, was es zurückgibt – verwirft alles, was die Anfrage gesendet hat, und lehnt ein späteres Update ab, das sie ändern würde, genau wie bei OwnedBy. Koppele es mit einem Zeilenfilter, der dem entspricht, was er setzt, sodass die Personen, unter denen ein Datensatz abgelegt wird, diejenigen sind, die ihn sehen können – hier RowsMatchingAny(r => r.RowsOfTheirAccount("customerid"), r => r.RowsOwnedByContact("customerid")), sodass WithoutStamping() die Registrierung die Spalte diesem Anbieter überlässt: Zwei, die eine Spalte anders setzen, scheitern beim Speichern.

Sicherheit auf Säulenebene

Die Spaltensicherheit ist opt-in. Ein Anbieter gewährt die Spalten, die er offenlegen möchte, und alles andere – einschließlich einer Spalte, die im nächsten Jahr zur Tabelle hinzugefügt wird – bleibt zurückgehalten, bis benannt wird. Die primäre ID des Datensatzes ist immer lesbar, da ein Datensatz, den das Framework nicht identifizieren kann, für niemanden nützlich ist.

Reads und Writes sind unabhängige Mengen: Eine Spalte kann lesbar, aber nicht beschreibbar sein (der Fall "Zeig das Kreditlimit, lass sie es nicht ändern"), oder beschreibbar, aber nicht lesbar. Benennen Sie sie mit Reading, Writing und ReadingAndWriting, oder wählen Sie eine Dimension vollständig mit ReadingAllColumns / WritingAllColumnsab:

Anmerkung

ReadingAllColumns() ist absichtlich etwas, das man tippen muss. Es ist für alles, was später hinzugefügt wird, nicht geöffnet, was nur dann der richtige Handel ist, wenn der Tisch wirklich öffentlich ist – also wird das System es nicht für dich übernehmen.

Das Schreiben kann sich auch zwischen dem Erstellen eines Datensatzes und dessen Änderung unterscheiden. Writing Deckt beides ab. WritingOnCreate Ermöglicht es dem Benutzer, eine Spalte beim Erstellen des Datensatzes festzulegen und sie von da an nur lesegeschützt zu machen – die Priorität eines Falls, die beim Protokollieren gewählt wird. WritingOnUpdate ist das Gegenteil: auf einem bestehenden Datensatz änderbar, aber nicht von Anfang an einstellbar. Beide machen die Spalte ebenfalls lesbar, wie Writing, und beide existieren auf TablePermissions für einen eigenen Anbieter. Sie spiegeln die separaten Berechtigungen zum Erstellen und Aktualisieren wider, die Dataverse eigene Feldsicherheit gewährt:

Das Framework setzt das Ergebnis auf jedem Pfad durch, bei dem Daten die Servergrenze überschreiten:

Anmerkung

Die primäre ID-Spalte einer Tabelle wird niemals zurückgehalten, egal was das Leseset angibt. Die ID ist Identität statt Daten – sie befindet sich bereits in der URL, die der Anrufer verwendet hat, um den Datensatz zu erreichen – und Zeilenschlüssel, Edit-Links, Subgrid-Beziehungen und Löschen lassen sich ohne sie auseinanderfallen. Eine Zulassungsliste, die die Spalten nennt, die eine Seite benötigt, und die ID vergisst, würde das Portal auseinandernehmen und nichts schützen.

Wie sich die Komponenten verhalten

Die Framework-Komponenten berücksichtigen eigenständig Spaltenberechtigungen – man verkabelt nichts. Eine Spalte, die der Benutzer nicht schreiben darf, wird überall dort gelesen und deaktiviert: Jeder Editor erkennt sie über seine gemeinsame Schreib-nur-Resolution, und das Raster gibt der Zelle keinen Inline-Editor, sodass sie auf einfachen Anzeigetext zurückfällt. Ein vom Verbraucher bereitgestellter readOnly="false" Spalte überschreibt das nicht – der Server würde den Speicherstand so oder so ablehnen.

Eine Spalte, die der Benutzer nicht lesen darf – eine maskierte – wird in beiden Stacks statt eines Editors durchgerendert <ColumnDisplayValue> . Das ist nicht nur eine Nettigkeit: Eine maskierte Spalte hat überhaupt keinen Wert, nur die Maske als ihren formatierten Wert , sodass ein an sie gebundener Editor leer erscheinen würde; ColumnDisplayValue liest den formatierten Wert und zeigt somit den Platzhalter an, egal welchen Typ die Spalte hat. Spalten, die durch Auslassung zurückgehalten werden, erreichen überhaupt keine Komponente – sie sind nicht im Datensatz und die Metadaten der Tabelle listen sie nicht auf.

Was der Kunde erhält

Spaltenberechtigungen erscheinen als Abbildung ColumnPermissions – logischer Name der Spalte auf ein ColumnSecurityPermission Flagpaar – für die Spalten, deren Zugriff eingeschränkt ist, was Write bedeutet, dass die Spalte bei einem bestehenden Datensatz geändert werden kann. Alles, was fehlt, hat vollen Zugriff, sodass eine uneingeschränkte Tabelle gar nichts enthält. Ein von sich aus abgerufener Datensatz trägt die Karte; gemeinsam abgerufene Datensätze teilen sich eine Karte, die einmal auf der Antwort gesendet wird, da die Berechtigungen dem Benutzer und der Tabelle gehören und nicht einer Zeile – beide Stack-Clients legen sie auf jeden Datensatz zurück, sodass das Lesen der Berechtigungen eines Datensatzes in beide Richtungen gleich funktioniert. Grid-Antworten melden sie auch pro Spalte auf ResolvedColumn.Permissions. Ein erstellter Datensatz hat noch keine eigene Karte, daher gibt NewRecordColumnPermissions auch der Endpunkt der Tabellenberechtigungen zurück – die gleiche Form, gemessen an dem, was beim Erstellen gesetzt wird – und beide Stacks RecordContext legen ihn auf einen neuen Datensatz für dich. Spalten, die durch Auslassung zurückgehalten wurden, fehlen absichtlich auf jeder Karte – das Weglassen existiert, sodass nichts in der Antwort die Spalte offenbart, und wenn man sie dort nennt, würde das rückgängig machen. Lies es selbst durch record.CanReadColumn(column) / record.CanWriteColumn(column) in Blazor oder die Matching canReadColumn / canWriteColumn Helfer aus @powerportalspro/core React.

Weglassen oder Maskieren

Standardmäßig wird eine zurückgehaltene Spalte maskiert: Der Datensatz trägt keinen Wert dafür und SecurityOptions.WithheldColumnMask (***** standardmäßig) als seinen formatierten Wert, sodass ein Formular oder Raster das Feld weiterhin rendert und deutlich macht, dass der Wert zurückgehalten und nicht leer ist. Die Maske ist gleich, egal ob die Spalte einen Wert hat oder nicht, also verbirgt sie auch diesen. Stattdessen wird SecurityOptions.WithheldColumnBehavior Omit die Spalte komplett aus dem Datensatz entfernt, als hätte die Abfrage nie danach gefragt, sodass nichts in der Antwort zeigt, dass die Spalte existiert – die richtige Wahl, wenn die Existenz der Spalte sensibel ist. Das Zurückhalten einer Spalte enthält auch jede Spalte, die sie erneut veröffentlicht – den Begleiter eines Lookups, der Basiswährungs-Zwilling einer Geldspalte –, sodass eine Ablehnungsliste, die eine Spalte nennt, nicht durch eine andere umgangen werden kann. Eine einzelne Tabelle kann die siteweite Wahl über TableColumnPermissions.WithheldColumnBehaviorüberschreiben.

Anmerkung

Paaren Sie eine maskierte Spalte mit einer Schreib-Ablehnung. Eine maskierte Spalte hat keinen Wert im Datensatz, sodass ein Aufrufer, der einen gesamten geladenen Datensatz zurückpostet, nichts dafür sendet – aber das Framework nimmt eine Speicher-Payload als Scheinwert an, sodass eine Anfrage, die die Spalte setzt, einschließlich der Maske, den gespeicherten Wert überschreibt, wenn die Spalte schreibbar ist. Die Schreib-Ablehnung ist es, die sie ablehnt.

Kolumnen, die eine weitere Kolumne neu veröffentlichen

Das Zurückhalten einer Spalte enthält auch jede Spalte, die denselben Wert unter einem zweiten Namen trägt. Dataverse erstellt diese für Sie: eine Abfrage …name und …yominame Partner, das Label einer Wahl und ein Basiswährungs-Zwilling für jede Währungsspalte – creditlimit_base neben creditlimit. Es handelt sich um gewöhnliche Spalten, daher sagt eine Denylist-Benennung creditlimit nichts über creditlimit_baseaus, und ohne diese würde ein maskierter Betrag direkt durch den Zwilling zurückkommen. Der Link stammt aus den eigenen Metadaten der Plattform und nicht aus einer Namensregel, daher gilt er auch für Ihre eigenen Spalten und gilt bei Lesungen, bei einer Abfrage, die den Begleiter explizit benennt, in Tabellenmetadaten, in Rasterspalten und bei Speicherständen.

Best Practice – an der Quelle filtern

Ein Fall, den das Framework für Sie nicht sieht: eine berechnete oder zusammenrollbare Spalte sowie die zusammengesetzten Spalten der Plattform — fullname, , yomifullnameund address1_composite deren Schwester. Dataverse gibt nicht an, welche Spalten sie füttern, daher heißt Zurückhaltung lastname nicht fullnameauch , und eine berechnete Spalte über einer von Ihnen abgelehnten Spalte zeigt trotzdem ihr Ergebnis an. Nennen Sie sie selbst im Leseset, wenn ihre Eingaben empfindlich sind. Eine Zulassungsliste (ColumnPermissions.Allow(…)) umgeht das Problem komplett, da nichts lesbar ist, bis Sie es benennen – was die bessere Standardeinstellung für eine Tabelle ist, die alles enthält, was es wert ist, zurückgehalten zu werden.

Anmerkung

Wenn mehrere Anbieter eine Tabelle abdecken, setzen sich ihre Spaltenmengen genauso zusammen wie ihre Operationen: additiv über die Rollen hinweg und unter MultiplePermissionHandlersBehavior innerhalb einer Gruppe. Ein Anbieter, der nur existiert, um Zeilen zu scopen und nichts über Spalten sagt, wird aus der Spaltenfaltung vollständig ausgelassen, sodass er weder das erweitert noch eingrenzt, was die anderen gewährten.

Dataverse-Native Security (Vorschau)

Das empfohlene Sicherheitsmodell ermöglicht es Dataverse selbst, die Sicherheit für Ihre Portalnutzer durchzusetzen, basierend auf der einheitlichen Dataverse-Sicherheitsfunktion von Power Pages. Anstatt Berechtigungshandler im Code zu schreiben, verwalten Sie den Zugriff mit Power Pages-Webrollen und Tabellenberechtigungen, die die Plattform in Dataverse-Sicherheitsrollen umwandelt, die Dataverse bei jeder Anfrage durchsetzt. Das Modell befindet sich derzeit in der Vorschau – sowohl Microsofts Funktion als auch Power Portals Pros Unterstützung dafür – und Power Portals Pro wird Microsofts Veröffentlichungsplan bis zur allgemeinen Verfügbarkeit folgen.

Wenn aktiviert, stellt PowerPortalsPro automatisch ein systemverwaltetes (C2) systemuser für jeden Portalkontakt bereit – bei der Registrierung für neue Kontakte und faul bei der Anmeldung für bestehende – zusammen mit dem powerpagesusermapping Datensatz, der den Kontakt, den Systemnutzer und Ihre Power Pages-Website verknüpft. Jeder Dataverse-Aufruf für die Sitzung imitiert dann diesen Systembenutzer, sodass die Sicherheitsrollen, die Power Pages mit deinen Webrollen und Tabellenberechtigungen synchronisiert, genau bestimmen, was der Nutzer sehen und tun kann. Die Sitzung trägt ein PortalUserType Off ContactStubUser , sodass Ihre Benutzeroberfläche diese bereitgestellten Benutzer immer von echten internen Benutzern unterscheiden kann.

Anmerkung

Um dieses Sicherheitsmodell zu verwenden, müssen Sie eine Power Pages-Website in Ihrer Dataverse-Umgebung erstellen – diese installiert die Microsoft-Framework-Komponenten und ermöglicht es Ihnen, die unified-security-Funktion zu aktivieren. Sie benötigen keinen bezahlten Power Pages-Plan und können die Website direkt nach der Installation und Aktivierung der Funktion löschen. Der von von belegte PowerPagesSiteId Power Pages-Site-Eintrag (powerpagesite) muss in der Umgebung vorhanden sein, da Benutzerzuordnungen und Synchronisation mit Sicherheitsrollen gegen ihn aufgelöst werden.

Aktivierung von Dataverse-Native-Sicherheit

Aktivieren Sie das System SecurityOptions auf Ihrem Server Program.csund geben Sie die ID Ihres Power Pages-Website-Datensatzes an:

Die Konfiguration wird beim Anwendungsstart überprüft: Wenn ProvisionSystemUsers aktiviert ist, PowerPagesSiteId muss gesetzt und auf einen bestehenden powerpagesite Datensatz aufgelöst werden, andernfalls startet die Anwendung nicht mit der Leitung.

Gewähren Sie Zugriff genau so wie Power Pages: Konfigurieren Sie Webrollen und Tabellenberechtigungen – in der Power Pages Management-App oder auf der Webrollen-Seite Ihres Portals in der Power Portals Pro Enhanced Authorization-Lösung – und weisen Sie Webrollen Kontakten zu (über die Management-App, programmatisch oder automatisch für neue Nutzer mit Regeln auf derselben Seite). Die Plattform synchronisiert diese in automatisch generierte Sicherheitsrollen (benannt PowerPages_*) und weist sie automatisch zu, wenn sich die Webrollenmitgliedschaft ändert – da die Konfiguration vollständig in Power Pages liegt, kann Ihr Portal problemlos zu oder von einer echten Power Pages-Seite wechseln. Beachten Sie, dass Rollen- und Privilegienänderungen von wenigen Sekunden bis zu ein paar Minuten dauern können, bis sie durch die Dataverse-Caches verbreitet werden, bevor sie wirksam werden.

Folgen Sie der Schritt-für-Schritt-Einrichtungsanleitung

Eine externe Anmeldung mit einem Kontakt abgleichen

Wenn sich jemand bei Microsoft, Google oder einem anderen externen Anbieter anmeldet, muss das Portal herausfinden, zu welchem bestehenden Kontakt – falls überhaupt – die Anmeldung gehört. Dies wird in zwei Schritten gelöst:

  1. Eine bestehende Verbindung. Wenn das Konto sich schon einmal angemeldet hat, verknüpft eine adx_externalidentity Zeile es bereits mit einem Kontakt. Das ist eine explizite, gespeicherte Aussage "Dieses Konto ist diese Person", sodass sie immer gewinnt und nie von den untenstehenden Einstellungen beeinflusst wird.
  2. Das E-Mail-Rückfallback. Da es noch keinen Link gibt, gleicht das Portal die vom Anbieter angegebene E-Mail-Adresse mit den Spalten des Kontakts ab. Dies ist der Schritt, den Sie konfigurieren können – und der Schritt, der entscheidet, ob ein zurückkehrender Kunde seinem bestehenden Kontakt beitritt oder eine Kopie erhält.

Standardmäßig werden zwei Spalten durchsucht, zuerst der Benutzername des Portals. Kontakte, die über das Portal erstellt werden, tragen adx_identity_username, während Kontakte, die vom Personal importiert oder eingegeben wurden, meist nur emailaddress1 – die Suche in beiden ermöglicht es einem bestehenden Kunden, sich einzuloggen und auf seinem eigenen Datensatz zu landen, statt auf einem neuen:

Die Reihenfolge ist wichtig: Es ist der Vorrang, nicht nur eine Liste. Die Spalten werden zusammen in einer einzigen Abfrage durchsucht, und die erste Spalte in Ihrer Liste, die zu etwas passt, entscheidet über den Gewinner – wenn also ein Kontakt die Adresse als Portal-Benutzername und ein anderer als emailaddress1Portal-Benutzername angibt, gewinnt der Benutzername-Treffer unter der Standardreihenfolge.

Führe weniger Spalten auf, um das Matching zu verengen: [ContactEmailColumn.IdentityUsername] beschränkt sie auf vom Portal erstellte Konten, und eine leere Liste schaltet den E-Mail-Fallback komplett aus, sodass ein bestehender externer Identitätslink die einzige Möglichkeit bleibt, wie ein Konto zu einem Kontakt aufgelöst werden kann. Füge hinzu ContactEmailColumn.EmailAddress2 und ContactEmailColumn.EmailAddress3 um es zu erweitern – sie werden absichtlich aus dem Standard weggelassen, aus dem unten genannten Grund.

Best Practice – an der Quelle filtern

Jede Spalte, die Sie angeben, ermöglicht es derjenigen, die eine E-Mail-Adresse kontrolliert, als Kontakt erkannt zu werden, der sie hält. Listen Sie nur Spalten auf, die Ihr Dateneingabeprozess als Eigentum des Kontakts selbst behandelt – wenn emailaddress2 Ihr Team die Adresse eines Assistenten oder einen gemeinsamen Firmenposteingang eingibt, kann sich durch die Listung jeder, der diesen Posteingang liest, als dieser Kontakt einloggen.

Best Practice – an der Quelle filtern

Das Matching macht die E-Mail-Adresse zu einer Identifikator, nicht nur zu einem Label – es entscheidet, welcher bestehende Kontakt ein Anmelder wird. Das Portal überspringt die Bestätigungs-E-Mail nur, wenn der Identitätsanbieter diese genaue Adresse tatsächlich verifiziert hat. Wenn die Adresse über die vom Anbieter angegebene eingegeben wurde oder der Anbieter sie nie verifiziert hat, wird ein Bestätigungslink gesendet und der externe Login wird erst mit dem Kontakt verknüpft, bis dieser Link gefolgt ist.

Welche Anmeldungen als verifiziert gelten, sind keine Eigenschaft des Anbieters. Google überprüft jede angegebene Adresse. Microsoft nicht: Ein persönliches Microsoft-Konto hat seine Adresse überprüft, aber ein Entra-Arbeits- oder Schulkonto liefert alles, was im Verzeichnisattribut mail enthalten ist, das ein Mieteradministrator auf beliebigen Wert in jeder Domain setzen kann – einschließlich einer Domain, die sein Mieter nicht besitzt. Das Portal liest stattdessen das Token des Anbieters: Ein persönliches Konto wird verifiziert, und ein Arbeits- oder Schulkonto wird nur verifiziert, wenn Entra für diese genaue Adresse bürgt – sein verified_primary_email oder verified_secondary_email Claim listet sie auf oder xms_edov gibt an, dass die Domain dem eigenen Mieter des Nutzers gehört. Entra sendet diese Ansprüche nur, wenn die App-Registrierung danach fragt (siehe Entra ID Sign-In Setup); ohne diese bestätigen Arbeits- und Schulanmeldungen beim ersten Mal per E-Mail.

Anmerkung

Diese Einstellungen gelten nur für externe Anmeldungen. Lokale Benutzername/Passwort-Anmeldung, Registrierung und Passwort-Zurücksetzung stimmen absichtlich auf adx_identity_username – der Passwort-Zurücksetzungsablauf mailt seinen Link an die eingegebene Adresse, sodass das Abgleichen der sekundären E-Mail-Spalten jemandem erlaubt, das Passwort einer anderen Person zurückzusetzen.

Nur bestehende Kontakte können sich anmelden

Standardmäßig kann jeder Portalnutzer werden: Die Registrierung oder das Anmelden bei einem externen Anbieter unter einer Adresse, die keinen Kontakt hat, schafft einen Kontakt. Wenn das Portal für Personen ist, die Sie bereits in Dataverse halten – Kunden, Mitglieder, Partner – schalten Sie die Anmeldung aus, und nur sie können sich anmelden:

Die Registrierungsseite und ihre Links verschwinden, und der Server weigert sich, einen Benutzer zu erstellen, egal wie er darum gebeten wird. Ein externer Anmelder findet trotzdem seinen oben beschriebenen Kontakt und verlinkt darauf; einer, der zu niemand passt, wird abgelehnt, anstatt einen Kontakt zu erstellen. Lokale Konten sind für Personen, die bereits einen haben, nicht betroffen.

Anmerkung

Eine verweigerte Anmeldung wird nur dann auf dem Bildschirm erklärt, wenn der Anbieter genau diese Adresse überprüft hat, denn dann hat die angemeldete Person bereits bewiesen, dass sie sie besitzt. Bei jeder anderen Adresse antwortet das Portal genauso wie bei einer Adresse mit Kontakt – "E-Mail prüfen" – und schickt der Adresse eine kurze Benachrichtigung, dass sie nicht registriert ist. Wenn man den Besucher direkt informiert, kann jeder Adressen ins Formular eingeben, um herauszufinden, wer ein Konto hat.

Die Mitteilung wird über den eigenen E-Mail-Absender des Portals verschickt. Ein Host, der sie durch einen eigenen E-Mail-Stack ersetzt, sollte ebenfalls ein ISignUpRefusalEmailSenderregistrieren; ohne eine wird die Ablehnung protokolliert und keine Mitteilung gesendet.

Eingebaute Basisklassen

Das Framework stellt Basisklassen bereit, um gängige Sicherheitsmuster zu vereinfachen:

API-Referenz

AuthorizePortalRoleAttribute Baureihe

Eigenschaften

Name
Typ
Default
Beschreibung
AuthenticationSchemesstring?
Policystring?
RoleNamesIReadOnlyList<string>
Die Rollennamen, die dieses Attribut erfordert, und jeder davon erfüllt ihn.
Rolesstring?
TypeIdObject
Name: AuthenticationSchemes
Typ: string?
Name: Policy
Typ: string?
Name: RoleNames
Typ: IReadOnlyList<string>
Beschreibung: Die Rollennamen, die dieses Attribut erfordert, und jeder davon erfüllt ihn.
Name: Roles
Typ: string?
Name: TypeId
Typ: Object

Methoden

Name
Parameter
Typ
Beschreibung
IsDefaultAttributebool
MatchObject obj
bool
Name: IsDefaultAttribute
Typ: bool
Name: Match
Parameter: Object obj
Typ: bool

ITablePermissionProvider Interface

Eigenschaften

Name
Typ
Default
Beschreibung
Tablestring
Logischer Name der Tabelle, auf die sich dieser Anbieter bezieht. Genau abgestimmt, also muss es die Dataverse logischer Name in Kleinbuchstaben.
Name: Table
Typ: string
Beschreibung: Logischer Name der Tabelle, auf die sich dieser Anbieter bezieht. Genau abgestimmt, also muss es die Dataverse logischer Name in Kleinbuchstaben.

Methoden

Name
Parameter
Typ
Beschreibung
GetPermissionsAsyncUserInfo user
Task<TablePermissions>
Was user könnte mit dieser Tabelle geschehen, und welche ihrer Spalten sie lesen dürfen und schreibe. Zurück TablePermissions.None für einen Benutzer, der eigentlich keinen Zugriff haben sollte. Die Operationen sind ein Tabellengatter, kein Zeilenfilter: grant TableSecurityPermission.Read ob der Benutzer eine der Tabellen sehen kann Zeilen und Scope, welche in Services.TableQueryContext). Spalten sind opt-in. Nichts ist lesbar oder beschreibbar, bis es benannt ist – gewährt TableSecurityPermission.Read Allein gibt nur die ID des Datensatzes frei. Verwendung Reading(System.String[]) und Writing(System.String[]) sie zu benennen, oder TablePermissions.AllColumns Um für diese Tabelle auf die Spaltensicherheit zu verzichten. Ein Anbieter, der nur existiert, um Zeilen zu scopen, kann die Spalten völlig unbemerkt lassen – und so etwas über sie, und es stellt keine Meinung dar, weder erweitert noch verengt er das andere. Anbieter auf dem Tisch gewährt. Nichts zu sagen, ist insgesamt als Fail-Closed gilt: wenn nein Der Anbieter nennt eine Spalte, keine ist lesbar. Einmal pro Tabelle und Benutzer aufgerufen und für die Anfrage zwischengespeichert, daher kann es genauso teuer sein wie es muss es sein.
GetQueryFilterAsyncTableQueryContext context
Task<TableQueryFilter>
Bereiche, auf welche Zeilen dieser Tabelle der Benutzer reagieren kann: ein Filter, der mit erstellt wurde Query.LogicalOperator), TableQueryFilter.AllRows für jeden Reihen die Operationen erlauben, oder null keine Reihen. Zeilen werden nicht geschlossen. Ein Anbieter muss genauso angeben, welche Zeilen er gewährt, genauso wie er es tun muss Benennen Sie die Spalten: null — oder ein Filter ohne Bedingungen — gewährt keine, also Wenn man vergisst, eine Tabelle zu scopen, lehnt sie ab, anstatt jede Zeile zu veröffentlichen. Zum Beispiel TableQueryFilter.AllRows Wenn jede Reihe das ist, was du meinst. Der Filter wird der Abfrage hinzugefügt, bevor Dataverse ihn ausführt, sodass Zeilen, die der Benutzer möglicherweise nicht sieht, Nie abgerufen. Es gilt für jede Abfrage, die das Portal für die Tabelle ausgibt: Raster, Nachschlage, Subgrids, Diagramme und Einzeldatensätze sowie der Pre-Flight-Abruf vor einem Update oder einer löschen – und das unterscheidet TableQueryContext.Operation . Es läuft außerdem unter beiden Sicherheitsmodellen, sodass sie bei Dataverse-nativer Sicherheit weiterhin in Kraft bleibt umgeht Services.UserInfo). Das Framework entscheidet, wie Filter kombiniert werden, nicht der Anbieter. Filter von Anbietern in derselben Gruppe überschneiden sich – sollen zwei Anbieter in einer Rolle zustimmen. Filtern aus Verschiedene Rollen vereinen sich, sodass das Behalten einer anderen Rolle das Sehende erweitert und so anpasst, wie die Operationen komponieren. Setzen PortalRoleOptions.CompositionBehavior Sie auf RoleCompositionBehavior.Restrictive Um sich auch über verschiedene Rollen hinweg zu überschneiden. Innerhalb einer Gruppe lässt ein antwortgebender null Anbieter der Gruppe keine Zeilen, und TableQueryFilter.AllRows Überlässt es den Filtern der anderen Anbieter, selbst zu entscheiden. Across Gruppen erweitert eine Gruppe gewährt TableQueryFilter.AllRows die Standardadditivität Union zu jeder Zeile – daher bedeutet der Filter einer Rolle nur etwas, wenn die anderen Gruppen gewähren Auch dieser Tischfilter.
Name: GetPermissionsAsync
Parameter: UserInfo user
Typ: Task<TablePermissions>
Beschreibung: Was user könnte mit dieser Tabelle geschehen, und welche ihrer Spalten sie lesen dürfen und schreibe. Zurück TablePermissions.None für einen Benutzer, der eigentlich keinen Zugriff haben sollte. Die Operationen sind ein Tabellengatter, kein Zeilenfilter: grant TableSecurityPermission.Read ob der Benutzer eine der Tabellen sehen kann Zeilen und Scope, welche in Services.TableQueryContext). Spalten sind opt-in. Nichts ist lesbar oder beschreibbar, bis es benannt ist – gewährt TableSecurityPermission.Read Allein gibt nur die ID des Datensatzes frei. Verwendung Reading(System.String[]) und Writing(System.String[]) sie zu benennen, oder TablePermissions.AllColumns Um für diese Tabelle auf die Spaltensicherheit zu verzichten. Ein Anbieter, der nur existiert, um Zeilen zu scopen, kann die Spalten völlig unbemerkt lassen – und so etwas über sie, und es stellt keine Meinung dar, weder erweitert noch verengt er das andere. Anbieter auf dem Tisch gewährt. Nichts zu sagen, ist insgesamt als Fail-Closed gilt: wenn nein Der Anbieter nennt eine Spalte, keine ist lesbar. Einmal pro Tabelle und Benutzer aufgerufen und für die Anfrage zwischengespeichert, daher kann es genauso teuer sein wie es muss es sein.
Name: GetQueryFilterAsync
Parameter: TableQueryContext context
Typ: Task<TableQueryFilter>
Beschreibung: Bereiche, auf welche Zeilen dieser Tabelle der Benutzer reagieren kann: ein Filter, der mit erstellt wurde Query.LogicalOperator), TableQueryFilter.AllRows für jeden Reihen die Operationen erlauben, oder null keine Reihen. Zeilen werden nicht geschlossen. Ein Anbieter muss genauso angeben, welche Zeilen er gewährt, genauso wie er es tun muss Benennen Sie die Spalten: null — oder ein Filter ohne Bedingungen — gewährt keine, also Wenn man vergisst, eine Tabelle zu scopen, lehnt sie ab, anstatt jede Zeile zu veröffentlichen. Zum Beispiel TableQueryFilter.AllRows Wenn jede Reihe das ist, was du meinst. Der Filter wird der Abfrage hinzugefügt, bevor Dataverse ihn ausführt, sodass Zeilen, die der Benutzer möglicherweise nicht sieht, Nie abgerufen. Es gilt für jede Abfrage, die das Portal für die Tabelle ausgibt: Raster, Nachschlage, Subgrids, Diagramme und Einzeldatensätze sowie der Pre-Flight-Abruf vor einem Update oder einer löschen – und das unterscheidet TableQueryContext.Operation . Es läuft außerdem unter beiden Sicherheitsmodellen, sodass sie bei Dataverse-nativer Sicherheit weiterhin in Kraft bleibt umgeht Services.UserInfo). Das Framework entscheidet, wie Filter kombiniert werden, nicht der Anbieter. Filter von Anbietern in derselben Gruppe überschneiden sich – sollen zwei Anbieter in einer Rolle zustimmen. Filtern aus Verschiedene Rollen vereinen sich, sodass das Behalten einer anderen Rolle das Sehende erweitert und so anpasst, wie die Operationen komponieren. Setzen PortalRoleOptions.CompositionBehavior Sie auf RoleCompositionBehavior.Restrictive Um sich auch über verschiedene Rollen hinweg zu überschneiden. Innerhalb einer Gruppe lässt ein antwortgebender null Anbieter der Gruppe keine Zeilen, und TableQueryFilter.AllRows Überlässt es den Filtern der anderen Anbieter, selbst zu entscheiden. Across Gruppen erweitert eine Gruppe gewährt TableQueryFilter.AllRows die Standardadditivität Union zu jeder Zeile – daher bedeutet der Filter einer Rolle nur etwas, wenn die anderen Gruppen gewähren Auch dieser Tischfilter.

TablePermissions Baureihe

Eigenschaften

Name
Typ
Default
Beschreibung
ColumnsTableColumnPermissions
Die Spalten, die der Benutzer lesen und schreiben darf. TableColumnPermissions.None Außer Etwas, das sie genannt wurde: Spaltenzugang wird gewährt, aber nie angenommen.
OperationsTableSecurityPermission
Die Operationen, die der Benutzer auf der Tabelle ausführen kann, als Flaggenwert. Dies ist eine Tabellenebene Gatter, kein Zeilenfilter – wenn TableSecurityPermission.Read der Benutzer es erlaubt Sehen Sie sich eine der Reihen der Tabelle an und scannen Sie welche durch Services.TableQueryContext).
Name: Columns
Typ: TableColumnPermissions
Beschreibung: Die Spalten, die der Benutzer lesen und schreiben darf. TableColumnPermissions.None Außer Etwas, das sie genannt wurde: Spaltenzugang wird gewährt, aber nie angenommen.
Name: Operations
Typ: TableSecurityPermission
Beschreibung: Die Operationen, die der Benutzer auf der Tabelle ausführen kann, als Flaggenwert. Dies ist eine Tabellenebene Gatter, kein Zeilenfilter – wenn TableSecurityPermission.Read der Benutzer es erlaubt Sehen Sie sich eine der Reihen der Tabelle an und scannen Sie welche durch Services.TableQueryContext).

Methoden

Name
Parameter
Typ
Beschreibung
AllColumnsTablePermissions
Verzichtet vollständig auf die Sicherheit auf Spaltenebene – jede Spalte ist lesbar und beschreibbar. Die Verhalten vor der Säulensicherheit, das eher ausgesprochen als geerbt wurde.
AllowTableSecurityPermission operations
TablePermissions
Fügt dem hinzu, operations was dieser Wert bereits bietet.
AllowingTableSecurityPermission operations
TablePermissions
Zuschüsse operations und keine Spalten. Kette Reading(System.String[]), Writing(System.String[]) oder TablePermissions.ReadingAllColumns um Spalten zu öffnen.
Readingstring[] columns
TablePermissions
Erlaubt das Lesen der benannten Spalten zusätzlich zu allen bereits erlaubten. Groß- und Schreibung-unempfindlich, Die Schreibweise des Maker-Portals funktioniert also ebenso gut wie der logische Name.
ReadingAllColumnsTablePermissions
Verzichtet auf die Lesesicherheit auf Spaltenebene für diese Tabelle: jede Spalte, einschließlich der hinzugefügten später an den Tisch. Absichtlich explizit – das Rahmenwerk wird es nicht annehmen.
ReadingAllColumnsExceptstring[] columns
TablePermissions
Meldet sich gegen die Spalten-Lesesicherheit ab, außer bei den benannten Spalten – jede Spalte außer jeder Spalte diese, einschließlich derjenigen, die später hinzugefügt wurden. Öffnet sich nicht für alles Neue, daher bevorzuge ich es Reading(System.String[]) auf Tabellen mit sensiblen Daten.
ReadingAndWritingstring[] columns
TablePermissions
Ermöglicht sowohl das Lesen als auch das Schreiben der benannten Kolumnen.
WithColumnsTableColumnPermissions columns
TablePermissions
Ersetzt die Spaltenregeln komplett, für einen Anbieter, der lieber eine Services.TableColumnPermissions sich selbst und dann die flüssigen Methoden verkettet.
WithholdingWithheldColumnBehavior behavior
TablePermissions
Wie die zurückgehaltenen Spalten in dieser Tabelle zurückkommen – weggelassen oder mit einem verdeckten Wert präsentiert werden. Überschreibt für diese Tabelle die seitenweite SecurityOptions.WithheldColumnBehavior Übersicht.
Writingstring[] columns
TablePermissions
Erlaubt das Schreiben der benannten Spalten – wenn ein Datensatz erstellt und aktualisiert wird – in Ergänzung zu allen bereits erlaubten. Eine Kolumne zu schreiben bedeutet nicht, sie zu lesen – nenne sie in Reading(System.String[]) auch, ob der Nutzer sehen sollte, was er geschrieben hat.
WritingAllColumnsTablePermissions
Verzichtet auf die Schreibsicherheit auf Spaltenebene für diese Tabelle: Der Benutzer kann jede beliebige Spalte schreiben, beim Erstellen und beim Aktualisieren. Ersetzt beide Schreibmengen, also ruf WritingOnCreate(System.String[]) / WritingOnUpdate(System.String[]) Danach, nicht davor.
WritingAllColumnsExceptstring[] columns
TablePermissions
Meldet sich gegen die Spalten-Schreibsicherheit ab, außer bei den benannten Spalten, die weiterhin lesegeschützt bleiben. Ersetzt beide Schreibmengen, also ruf WritingOnCreate(System.String[]) / WritingOnUpdate(System.String[]) Danach, nicht vorher.
WritingOnCreatestring[] columns
TablePermissions
Erlaubt das Setzen der benannten Spalten, wenn ein Datensatz erstellt wird, und erst dann: sobald er existiert sie sind schreibgeschützt, selbst wenn ein früherer Aufruf — Writing(System.String[]), TablePermissions.WritingAllColumns — machte sie beschreibbar. Die Priorität eines Falls, gewählt, wann er es ist Protokolliert und von da an behoben. Nennen Sie es nach einem beliebigen WritingAllColumn..., der das ersetzt Beide schreiben Mengen. Wie , impliziert das kein Lesen Writing(System.String[]).
WritingOnUpdatestring[] columns
TablePermissions
Erlaubt es, die benannten Spalten in einem bestehenden Datensatz zu ändern, sie aber nicht zu setzen, wenn es der Fall ist erstellt, selbst wenn ein früherer Anruf sie beschreibbar gemacht hat – Resolution merkt nur, dass das bedeutet etwas, wenn der Fall einmal existiert. Nennen Sie es nach jedem beliebigen WritingAllColumns..., der das ersetzt Beide schreiben Mengen. Wie , impliziert das kein Lesen Writing(System.String[]).
Name: AllColumns
Typ: TablePermissions
Beschreibung: Verzichtet vollständig auf die Sicherheit auf Spaltenebene – jede Spalte ist lesbar und beschreibbar. Die Verhalten vor der Säulensicherheit, das eher ausgesprochen als geerbt wurde.
Name: Allow
Parameter: TableSecurityPermission operations
Typ: TablePermissions
Beschreibung: Fügt dem hinzu, operations was dieser Wert bereits bietet.
Name: Allowing
Parameter: TableSecurityPermission operations
Typ: TablePermissions
Beschreibung: Zuschüsse operations und keine Spalten. Kette Reading(System.String[]), Writing(System.String[]) oder TablePermissions.ReadingAllColumns um Spalten zu öffnen.
Name: Reading
Parameter: string[] columns
Typ: TablePermissions
Beschreibung: Erlaubt das Lesen der benannten Spalten zusätzlich zu allen bereits erlaubten. Groß- und Schreibung-unempfindlich, Die Schreibweise des Maker-Portals funktioniert also ebenso gut wie der logische Name.
Name: ReadingAllColumns
Typ: TablePermissions
Beschreibung: Verzichtet auf die Lesesicherheit auf Spaltenebene für diese Tabelle: jede Spalte, einschließlich der hinzugefügten später an den Tisch. Absichtlich explizit – das Rahmenwerk wird es nicht annehmen.
Name: ReadingAllColumnsExcept
Parameter: string[] columns
Typ: TablePermissions
Beschreibung: Meldet sich gegen die Spalten-Lesesicherheit ab, außer bei den benannten Spalten – jede Spalte außer jeder Spalte diese, einschließlich derjenigen, die später hinzugefügt wurden. Öffnet sich nicht für alles Neue, daher bevorzuge ich es Reading(System.String[]) auf Tabellen mit sensiblen Daten.
Name: ReadingAndWriting
Parameter: string[] columns
Typ: TablePermissions
Beschreibung: Ermöglicht sowohl das Lesen als auch das Schreiben der benannten Kolumnen.
Name: WithColumns
Parameter: TableColumnPermissions columns
Typ: TablePermissions
Beschreibung: Ersetzt die Spaltenregeln komplett, für einen Anbieter, der lieber eine Services.TableColumnPermissions sich selbst und dann die flüssigen Methoden verkettet.
Name: Withholding
Parameter: WithheldColumnBehavior behavior
Typ: TablePermissions
Beschreibung: Wie die zurückgehaltenen Spalten in dieser Tabelle zurückkommen – weggelassen oder mit einem verdeckten Wert präsentiert werden. Überschreibt für diese Tabelle die seitenweite SecurityOptions.WithheldColumnBehavior Übersicht.
Name: Writing
Parameter: string[] columns
Typ: TablePermissions
Beschreibung: Erlaubt das Schreiben der benannten Spalten – wenn ein Datensatz erstellt und aktualisiert wird – in Ergänzung zu allen bereits erlaubten. Eine Kolumne zu schreiben bedeutet nicht, sie zu lesen – nenne sie in Reading(System.String[]) auch, ob der Nutzer sehen sollte, was er geschrieben hat.
Name: WritingAllColumns
Typ: TablePermissions
Beschreibung: Verzichtet auf die Schreibsicherheit auf Spaltenebene für diese Tabelle: Der Benutzer kann jede beliebige Spalte schreiben, beim Erstellen und beim Aktualisieren. Ersetzt beide Schreibmengen, also ruf WritingOnCreate(System.String[]) / WritingOnUpdate(System.String[]) Danach, nicht davor.
Name: WritingAllColumnsExcept
Parameter: string[] columns
Typ: TablePermissions
Beschreibung: Meldet sich gegen die Spalten-Schreibsicherheit ab, außer bei den benannten Spalten, die weiterhin lesegeschützt bleiben. Ersetzt beide Schreibmengen, also ruf WritingOnCreate(System.String[]) / WritingOnUpdate(System.String[]) Danach, nicht vorher.
Name: WritingOnCreate
Parameter: string[] columns
Typ: TablePermissions
Beschreibung: Erlaubt das Setzen der benannten Spalten, wenn ein Datensatz erstellt wird, und erst dann: sobald er existiert sie sind schreibgeschützt, selbst wenn ein früherer Aufruf — Writing(System.String[]), TablePermissions.WritingAllColumns — machte sie beschreibbar. Die Priorität eines Falls, gewählt, wann er es ist Protokolliert und von da an behoben. Nennen Sie es nach einem beliebigen WritingAllColumn..., der das ersetzt Beide schreiben Mengen. Wie , impliziert das kein Lesen Writing(System.String[]).
Name: WritingOnUpdate
Parameter: string[] columns
Typ: TablePermissions
Beschreibung: Erlaubt es, die benannten Spalten in einem bestehenden Datensatz zu ändern, sie aber nicht zu setzen, wenn es der Fall ist erstellt, selbst wenn ein früherer Anruf sie beschreibbar gemacht hat – Resolution merkt nur, dass das bedeutet etwas, wenn der Fall einmal existiert. Nennen Sie es nach jedem beliebigen WritingAllColumns..., der das ersetzt Beide schreiben Mengen. Wie , impliziert das kein Lesen Writing(System.String[]).

AuthClientOptions Baureihe

Eigenschaften

Name
Typ
Default
Beschreibung
LocalAccountsEnabledbool
True
Ob das Portal lokale Benutzername-/Passwortkonten akzeptiert. Standard: True. Für ein rein internes Portal auf falsch gestellt (nur Microsoft/Entra-Anmeldung). Dadurch werden lokale Konten auf dem Server ausgeschaltet, nicht nur in der Benutzeroberfläche. MapAuthEndpoints Es wird keine Passwortanmeldung, Registrierung, Passwortzurücksetzung, Einstellung oder Änderung eines Passwort oder Zwei-Faktor-Management, also diese Routen 404. Die Identitätsschicht des Portals verweigert außerdem die Passwortanmeldung und weigert sich, ein Passwort zu erstellen, hinzuzufügen, zu ändern oder zurückzusetzen, Das gilt auch für servergenerierte Kontoseiten. Anmeldung über externe Anbieter, E-Mail-Bestätigung, Profil, externes Login-Management, Download persönlicher Daten und Kontolöschungen bleiben unbeeinträchtigt. Clients lesen es, um das lokale Anmeldeformular und die Seiten zum Registrieren / Passwort-Zurücksetzen zu verbergen. Passwörter, die bereits für bestehende Konten gespeichert sind, bleiben im Dataverse, können aber nicht mehr gespeichert werden Früher habe ich mich eingeloggt.
SignUpEnabledbool
True
Ob das Einloggen einen Portal-Nutzer erstellen kann. Standard : jeder, der sich registriert, oder Meldet sich über einen externen Anbieter mit einer Adresse an, die kein Kontakt hat, und erhält einen neuen Kontakt. Auf falsch gestellt, sodass nur Personen mit bereits Kontakt sich anmelden können. Auch wenn sie ausgeschaltet ist, entspricht eine externe Anmeldung weiterhin einem bestehenden Kontakt – über einen früheren Link oder durch die E-Mail-Spalten in SecurityOptions.ContactMatching – und Links dazu, indem ein E-Mailing-Newsletter Bestätigung zuerst, wenn der Anbieter nicht für die Adresse bürgt. Ein Anmelder passt zu niemandem wird abgelehnt, anstatt einen Kontakt zu erstellen. Die Person, die sich anmeldet, wird dies nur dann mitgeteilt, wenn die Der Anbieter hat die Adresse überprüft; ansonsten wird die Adresse per Post mit einer Mitteilung und der Anmeldung erfolgt als eine übereinstimmende Adress beantwortet, daher kann das Formular nicht verwendet werden, um herauszufinden, welche Adressen eine Kontakt. MapAuthEndpoints kartiert keine Registrierung, sodass die 404er und die Die Identitätsschicht des Portals weigert sich, einen Benutzer zu erstellen, was Server-gerenderte Konten abdeckt Seiten auch. Kunden lesen es, um die Registerseite und den Link zu verbergen und um eine verweigerte Anmeldung zu erklären.
Name: LocalAccountsEnabled
Typ: bool
Default: True
Beschreibung: Ob das Portal lokale Benutzername-/Passwortkonten akzeptiert. Standard: True. Für ein rein internes Portal auf falsch gestellt (nur Microsoft/Entra-Anmeldung). Dadurch werden lokale Konten auf dem Server ausgeschaltet, nicht nur in der Benutzeroberfläche. MapAuthEndpoints Es wird keine Passwortanmeldung, Registrierung, Passwortzurücksetzung, Einstellung oder Änderung eines Passwort oder Zwei-Faktor-Management, also diese Routen 404. Die Identitätsschicht des Portals verweigert außerdem die Passwortanmeldung und weigert sich, ein Passwort zu erstellen, hinzuzufügen, zu ändern oder zurückzusetzen, Das gilt auch für servergenerierte Kontoseiten. Anmeldung über externe Anbieter, E-Mail-Bestätigung, Profil, externes Login-Management, Download persönlicher Daten und Kontolöschungen bleiben unbeeinträchtigt. Clients lesen es, um das lokale Anmeldeformular und die Seiten zum Registrieren / Passwort-Zurücksetzen zu verbergen. Passwörter, die bereits für bestehende Konten gespeichert sind, bleiben im Dataverse, können aber nicht mehr gespeichert werden Früher habe ich mich eingeloggt.
Name: SignUpEnabled
Typ: bool
Default: True
Beschreibung: Ob das Einloggen einen Portal-Nutzer erstellen kann. Standard : jeder, der sich registriert, oder Meldet sich über einen externen Anbieter mit einer Adresse an, die kein Kontakt hat, und erhält einen neuen Kontakt. Auf falsch gestellt, sodass nur Personen mit bereits Kontakt sich anmelden können. Auch wenn sie ausgeschaltet ist, entspricht eine externe Anmeldung weiterhin einem bestehenden Kontakt – über einen früheren Link oder durch die E-Mail-Spalten in SecurityOptions.ContactMatching – und Links dazu, indem ein E-Mailing-Newsletter Bestätigung zuerst, wenn der Anbieter nicht für die Adresse bürgt. Ein Anmelder passt zu niemandem wird abgelehnt, anstatt einen Kontakt zu erstellen. Die Person, die sich anmeldet, wird dies nur dann mitgeteilt, wenn die Der Anbieter hat die Adresse überprüft; ansonsten wird die Adresse per Post mit einer Mitteilung und der Anmeldung erfolgt als eine übereinstimmende Adress beantwortet, daher kann das Formular nicht verwendet werden, um herauszufinden, welche Adressen eine Kontakt. MapAuthEndpoints kartiert keine Registrierung, sodass die 404er und die Die Identitätsschicht des Portals weigert sich, einen Benutzer zu erstellen, was Server-gerenderte Konten abdeckt Seiten auch. Kunden lesen es, um die Registerseite und den Link zu verbergen und um eine verweigerte Anmeldung zu erklären.