Segurança da mesa

O Power Portals Pro protege os dados em três níveis: quais tabelas o usuário pode tocar, quais colunas dessas tabelas pode ver e alterar, e quais linhas retornam. Os três são decididos em um único registro por tabela. Descreva esse registro com AddTableAccess — é a forma de conceder uma tabela e o que os templates de projeto usam para cada tabela que eles registrarem. Quando uma regra é indescritível, as mesmas três respostas podem ser escritas como uma ITablePermissionProvider classe; ambas produzem a mesma coisa e compõem da mesma forma. Nada é concedido até que uma delas o diga: uma tabela que nenhum registro cobre é inacessível, que é o padrão fail-closed.

Dica

Você não precisa escrever isso a partir de uma página em branco. Projetos gerados entregam uma secure-a-table habilidade: peça ao seu agente de codificação para garantir uma tabela e ele trabalha através de qual tabela, para quem ela é, quais linhas, quais operações e quais colunas, então escreve o registro e faz as alterações correspondentes no Dataverse através do servidor Power Portals Pro MCP — criando o papel do portal se o acesso estiver vinculado ao papel e concedendo ao usuário do aplicativo os privilégios que as respostas sugerem. Depois, check_setup reporta qualquer tabela à qual suas páginas estejam vinculadas e que nada conceda acesso, e qualquer registro que opte por não participar da segurança das colunas. Veja Como Começar → Servidor MCP.

Todos, ou Só Algumas Pessoas

Cada registro diz para quem é, e há duas respostas. Registre-o no portal e ele aplica a um público seus nomes-código — todo mundo, ou cada usuário logado. Registre-o dentro AddPortalRole e ele se aplica aos detentores desse papel, que é uma decisão de dados que o administrador toma no Dataverse. O acesso em si é descrito da mesma forma em ambos.

Registro Aplica-se a Para mudar quem recebe
AddTableAccess("account", t => t.ForSignedInUsers()…) todos que a plateia cobre, a cada pedido editar o código e redistribuir
AddPortalRole("Credit Manager", role => role.WithTableAccess("account", …)) contatos que ocupavam aquele Papel de Portal, e mais ninguém assignar ou desatribuir a função no Dataverse — sem implantação

Uma tabela pode ser registrada uma vez para cada público em todo o portal — ForEveryone() para o que qualquer pessoa pode alcançar, ForSignedInUsers() para o que o login adiciona — e as duas somam. Um visitante recebe a primeira; um usuário logado recebe ambas, com cada operação restrita às linhas do registro que a concede. Com os dois registros abaixo, todos lêem todos os artigos, e um autor logado também pode escrever um e editar o seu próprio:

Os papéis somam; eles nunca subtraem. O acesso do usuário é o registro em todo o portal mais cada função que ele ocupa, unida — então a função para todo o portal é o piso em que todos estão, e um papel só pode aumentá-lo. Um papel não pode recuperar uma coluna ou linha que o registro em todo o portal concedeu; para reter algo da maioria das pessoas, conceder em um papel em vez de em todo o portal. (Definido SecurityOptions.Roles.CompositionBehavior para Restrictive se você precisar que todos os grupos concordem.)

Então: se todo usuário desse tipo tiver acesso, registre-o no portal. Se ao menos alguns deverem — e qual pessoa é uma pergunta cuja resposta muda sem liberação — coloquem em um papel. O registro de função não concede nada até que alguém crie um registro de Portal com esse nome e o atribua, por isso é possível sentar em um projeto novo sem causar dano.

Descrevendo o Acesso de uma Tabela

A maioria das tabelas quer as mesmas poucas regras: para quem é a tabela, quais linhas alcançam, o que podem fazer e quais colunas veem. AddTableAccess diz o registro dos quatro em um e produz um ordinário ITablePermissionProvider — nada a jusante sabe a diferença. O que isso compra é que as três decisões que precisam concordar (o filtro, a criação e as colunas graváveis) são tomadas uma vez em vez de três.

Um público, um escopo de linha e Allow(…) todos são necessários. Nenhum deles tem padrão, porque todo padrão plausível é uma forma de publicar dados deixando algo de fora — e um registro que erra falha na inicialização em vez de em produção.

Escopos de Linha

O escopo filtra todas as consultas da tabela — grades, consultas, subgrades, gráficos e a busca antes de um save ou delete. Os escopos nomeados cobrem as formas que os portais continuam precisando:

Quais linhas Escopo No criar
Cada fileira AllRows() Nada definido
Os próprios registros do usuário RowsOwnedByContact("customerid") a busca está configurada para eles
Registros de colegas, na mesma conta RowsOfTheirAccount("customerid") a busca é configurada para a conta deles
Registros pendurados em um dos pais que eles conseguem alcançar RowsViaParent("salesorderid", "salesorder", p => …) Nada definido — o acesso dos pais decide
Registros que apontam para eles de mais de uma forma RowsMatchingAny(r => r.RowsOwnedByContact("customerid"), r => r.RowsOfTheirAccount("customerid")) O que o primeiro escopo de propriedade listou define
A disputa de contatos deles OwnRecordOnly() não criar

Os escopos de propriedade definem a coluna quando um registro é criado, após as verificações de permissões: o usuário não precisa de acesso de escrita a ela nem de Append To na tabela para a qual ela aponta, o valor vem da sessão e não da solicitação, e um save posterior que mudaria isso é recusado. É isso que mantém um registro criado dentro do filtro ao qual está sujeito. Use OwnedBy('column') quando a coluna proprietária não for aquela que filtrou as linhas, e WithoutStamping() quando um plugin já a configura.

Quando Ler e Mudar Diferem

One scope responde a todas as operações, a menos que você diga o contrário. RowsForWriting Reduz as linhas que um usuário pode alterar sem restringir as linhas que pode ver — "todos lêem cada contato, cada um edita apenas o seu" é essa distinção e nada mais — e RowsForDeleting reduz a destruição ainda mais, porque poder corrigir um registro não é o mesmo que poder destruí-lo. Cada um volta para o que está acima, então um registro que não faz distinção não faz diferença nenhum. Criações não são afetadas: ainda não há linha para filtrar.

Quando as lunetas nomeadas não encaixam

RowsMatching Usa um filtro próprio sem sair do registro. Dê FetchXML — um <filter> elemento ou um todo <fetch> cujos filtros e joins são copiados, com {currentUserId} para o contato logado — ou um callback que roda por requisição e retorna o FetchXML, composto pelo que seus serviços respondem, ou um filtro que ele construiu. Ambos recebem o mesmo TableQueryContext que um provedor recebe, então eles sabem quem está perguntando e se as linhas estão prestes a ser lidas, atualizadas ou excluídas. Não devolver nada não concede linhas: TableQueryFilter.AllRows é como você diz cada linha.

Descrevendo o Acesso de um Cargo

Dentro AddPortalRole do papel está o público, então o registro não nomeia outro. Papéis somam e nunca subtraem: o acesso do usuário são os registros em todo o portal mais todos os cargos que ele ocupa, sindicalizados. Os próprios papéis do portal — o que são, como são atribuídos e como compõem — são a próxima seção.

Nota

Uma classe de provedor permanece como forma de expressar tudo o que uma descrição não pode, e ela compõe de forma idêntica — AddTablePermissionProvider<T> e WithPermissions<T> permanece inalterada. Os projetos gerados não entregam mais uma: toda tabela registrada é descrita, incluindo contact e o papel de Gerente de Crédito.

Funções no Portal

Um papel de portal é a forma preferida de proteger um portal. Ele vincula os provedores de permissão a um nome que os administradores atribuem aos contatos no Dataverse, de modo que os provedores se aplicam apenas às pessoas que ocupam essa função — e quem a detém são dados, não código. Um provedor registrado Program.cs diretamente se aplica a todos os usuários, em comparação.

A divisão é deliberada. O Dataverse detém os nomes e as atribuições, que um administrador gerencia no aplicativo orientado ao modelo. Seu código é dono do significado de cada nome. Conceder ou revogar o acesso de alguém é então uma mudança de dados: sem reconstrução, sem reimplantação.

1. Criar o papel e atribuí-lo

Crie um registro de Papel no Portal e atribua-o aos contatos que deveriam tê-lo. O registro de função contém apenas um nome e uma descrição — nenhum dado de permissão está presente no Dataverse.

2. Vincular o papel aos seus provedores

Compare o nome do registro de vaga e liste o que ele concede. Os tipos de prestadores são registrados para você, então você não os registra pessoalmente.

Esse último ponto importa: nunca registre também o provedor de um papel com AddTablePermissionProvider<T>(). Isso coloca o cargo no conjunto global e concede a todos, anulando silenciosamente o cargo. Reserve AddTablePermissionProvider<T>() regras que realmente se apliquem a todos os usuários.

Como os papéis se combinam

As permissões de um usuário vêm dos provedores registrados globalmente, além de cada função que ocupa, e esses grupos se juntam assim:

Dica

Na composição aditiva, nada nega — algo permanece fechado apenas enquanto nenhum grupo o abre. Um provedor registrado globalmente é o local certo para uma regra que se aplica a todo usuário, porque ela está sempre no fold, mas não é um veto: um papel que concede a operação, ou nomeia a coluna, a reabre. Para manter algo fechado, quaisquer que sejam os papéis que um usuário tenha, conceda em nenhum papel — ou defina SecurityOptions.Roles.CompositionBehavior para Restrictive, onde todo grupo tem que concordar.

Papéis nas páginas e navegação

Os nomes dos papéis chegam ao navegador como reivindicações padrão ASP.NET de papéis, então a autorização de página e a interface condicional funcionam sem nada extra:

A pilha React lê os mesmos nomes de auth.user.roles, e <AuthorizedView roles="Dealer"> porta o conteúdo da mesma forma. Logins internos (usuários do sistema) carregam aqui seus nomes de papéis de segurança do Dataverse, então uma verificação cobre ambos os tipos de usuário.

Autorização para o tipo certo de função

Um papel de portal e um papel de segurança do Dataverse podem compartilhar um nome, e [Authorize(Roles = "…")] não podem diferenciá-los — ele corresponde à reivindicação de papel não tipado, que carrega ambos. Dois atributos fazem a pergunta mais restrita:

Os nomes dos papéis vão literalmente: vírgulas, dois-pontos e aspas são todos aceitáveis, porque o nome nunca é separado de uma lista. Empilhar dois atributos requer ambos, do mesmo jeito que os atributos empilhados [Authorize] sempre fizeram; listar dois nomes em um atributo exige qualquer um dos dois. A mesma verificação está disponível no código como User.IsInPortalRole("Dealer") e User.IsInSecurityRole("Sales Manager").

A mesma distinção na marcação Blazor. <AuthorizeView Roles="…"> lê a reivindicação de papel não tipado e, portanto, carrega a mesma ambiguidade do atributo plain; <PortalRoleView> pede um tipo. Dê / PortalRole SecurityRole para um único nome, ou PortalRoles / SecurityRoles para vários — uma coleção em vez de uma cadeia separada por vírgulas, porque os nomes do Dataverse rotineiramente contêm vírgulas:

React <AuthorizedView> assume os mesmos dois portais, junto com o existente roles . Fornecer vários nomes em um portal significa qualquer um deles; fornecer dois portais significa ambos. Os predicados atrás deles — hasPortalRole, hasSecurityRole, hasRole — são exportados para verificações imperativas:

Boa prática — filtre na fonte

Procure esses documentos sempre que o que está sendo protegido for realmente administrativo. Criar um papel de portal é um padrão propositalmente mais baixo do que receber um papel de segurança no Dataverse, então uma verificação que aceite permite que um administrador distribua acesso que o papel do Dataverse estava protegendo simplesmente nomeando um papel de portal em homenagem a ele.

Nota

Os papéis não são gratuitos. Cada um que o usuário mantém é escrito no cookie de autenticação duas vezes — uma como a reivindicação padrão de papel, então [Authorize(Roles)] funciona, e outra como a reivindicação específica de tipo que torna possíveis as verificações acima — que mede cerca de 160 bytes por função. Cerca de quinze papéis por usuário ainda acomodam um único cookie; além disso, o cookie se divide em blocos, e a primeira coisa a ceder geralmente é o limite de cabeçalho de um proxy reverso, que reporta um opaco 400 em vez de algo que mencione papéis. Prefira alguns papéis amplos em vez de muitos restritos.

Dando a novos usuários um papel inicial

Nomeie os papéis que toda nova conta deve ter e o papel que se aplica aos visitantes desconectados:

Ou decidir no Dataverse, sem uma liberação. A tabela de Configuração de Funções do Portal emparelha uma função com um modo de atribuição, e um administrador pode alterar quem recebe o quê do aplicativo orientado ao modelo:

Quando as funções dependem da pessoa — seu domínio de e-mail, o provedor com quem ela fez login, um convite — registre-se e IPortalRoleAssignmentProvider em vez disso. Todo provedor registrado é consultado, então o seu adiciona à lista configurada em vez de substituí-la. De qualquer forma, a atribuição é executada uma vez, quando a conta é criada; ela nunca é reaplicada no login, então uma função removida por um administrador permanece removida.

Nota

Um usuário adquire uma função recém-atribuída ao sair e entrar novamente — ao fazer login relê seus papéis. As atribuições de papéis são armazenadas em cache por usuário por 24 horas, então, para aplicar uma alteração a alguém que já está logado, limpe o cache de Papéis do Portal da área de administração do site: a sessão deles o retoma na próxima atualização, em dez minutos, e um papel removido para de funcionar e assim que um papel adicionado começa. A tabela de Configuração de Função do Portal fica em cache separadamente por quinze minutos, então uma linha adicionada ali alcança o próximo registro por conta própria — limpe o cache "PortalRoleConfiguration" para torná-lo imediato. Desativar uma linha de configuração impede que ela distribua seu papel, da mesma forma que desativar um papel o revoga.

Escrevendo um provedor em vez disso

Busque uma classe quando uma descrição não pode dizer o que você quer dizer — uma regra que depende de algo que só seu código sabe, ou uma que precisa inspecionar o registro em andamento. ITablePermissionProvider É o que todo registro se torna de qualquer forma: um provedor governa uma tabela, respondendo o que um usuário pode fazer com ela, quais colunas pode ler e escrever, e — através do filtro de consulta abaixo — quais linhas ele pode ver. Um registro descrito e um escrito compõem de forma idêntica, então um portal pode usar ambos, e uma tabela pode ser concedida por um e ampliada pelo outro.

A interface possui um membro obrigatório. GetPermissionsAsync recebe um UserInfo que carrega o ID do usuário, seus papéis de portal e seus papéis de segurança do Dataverse, e retorna um TablePermissions descrevendo tudo que o usuário recebe:

Cadastrando um provedor

Um provedor registrado dessa forma se aplica a todos os usuários, logados ou não:

Essa também é a única forma de tirar algo de todos: os papéis compõem aditivamente por padrão, então um papel pode adicionar acesso, mas nunca removê-lo. Restrições em todo o portal pertencem a um provedor registrado globalmente, que sempre faz parte do grupo.

Operações

TablePermissions.Operations é um TableSecurityPermission valor de bandeira — Read, Create, Write, Delete, e Append AppendTo. Duas coisas que valem a pena saber sobre ele:

Nota

Não existe deliberadamente um gancho de "inspecionar cada linha após carregá-la". Filtrar dessa forma quebra a paginação — uma página de 50 retorna com menos — faz com que o total de contagens esteja errado e paga ao Dataverse para recuperar as linhas que ele depois descarta. O escopo da consulta, em vez disso, mantém a paginação e as contagens corretas por construção.

Boa prática — filtre na fonte

Escopar dados na consulta, não depois dele. O framework deliberadamente não oferece nenhum hook que inspecione cada linha depois de buscada: filtrar dessa forma quebra a paginação (uma página de 50 chega a menos), faz a contagem total estar errada e paga ao Dataverse para recuperar as linhas que ele então descarta. GetQueryFilterAsync adiciona as condições antes da consulta executar, então paginação e contagens permanecem corretas por construção e as linhas que um usuário pode não ver nunca são recuperadas.

Segurança em nível de linha

GetQueryFilterAsync retorna um filtro que o framework adiciona à consulta antes da execução do Dataverse, então linhas que o usuário pode não ver nunca são buscadas. Ele se aplica a toda consulta que o portal emite para a tabela — grades, consultas, subgrades, gráficos e cargas de registro único — e roda sob ambos os modelos de segurança, permanecendo em vigor mesmo onde a segurança nativa do Dataverse contorna o portão de operação.

Construa o filtro com context.CreateFilter() e retorne-o; retornando null significa sem restrição de linha. O contexto carrega o usuário atual como EntityReferenceum , os papéis que ele possui e para que as linhas estão prestes a ser usadas. Condições são adicionadas pela mesma FetchXMLBuilder API usada em todos os outros lugares: FetchXMLBuilder

Este provedor concede três colunas de contact e escopa cada consulta de contato ao registro do usuário logado:

Leitura, atualização e exclusão

TableQueryContext.Operation Diz por que as linhas estão sendo buscadas, para que um provedor possa defini-las de forma diferente para cada uma:

Como vários filtros se combinam

Uma tabela pode ter mais de um provedor — um registrado globalmente, mais um de cada função que o usuário ocupa. O framework decide como seus filtros se combinam, então um provedor nunca precisa saber o que os outros fizeram:

Nota

Linhas falham fechadas, como colunas: um provedor que retorna null — ou um filtro sem condições — não concede linhas , e dentro de um grupo que esvazia o grupo. Cada linha precisa ser solicitada com TableQueryFilter.AllRows. É aí que reside a assimetria: a união de toda linha com qualquer coisa é toda linha, então se qualquer grupo que concede a tabela responde AllRows, a tabela retorna sem filtro, por mais cuidadosamente que os outros papéis tenham definido o escopo. Isso é o que significa composição aditiva, mas é a única forma pelo filtro de um papel parecer que está sendo ignorado.

Filtragem através de uma tabela relacionada

AddLink junta uma tabela para que o filtro possa testar suas colunas. Coloque o teste no filtro em vez de no link — condições dentro do filtro continuam funcionando quando a estrutura relaxa a junção para fora, e as condições no link não iriam:

Nota

A junção acima chega até muitas linhas, então o Dataverse devolve a conta uma vez por membro — uma grade repetindo linhas e um total que as conta. O framework reconhece essa forma e marca a consulta distinct, projetando a chave primária da tabela para que a deduplicação só remova as linhas que a junção adicionou. Uma junção que se estende para cima , juntando-se à própria chave primária da tabela relacionada, corresponde no máximo a uma linha e fica exatamente como antes. De qualquer forma, você escreve o filtro e nada mais — mas vale saber que uma junção não é gratuita, e que uma regra que você pode expressar como condições planas nas próprias colunas da tabela é a forma mais barata.

Dica

Quando uma tabela precisa de um escopo diferente para cada função, você ainda pode escrever um provedor e ramificar — context.User.PortalRoles mas não precisa mais. Dois papéis podem carregar seu próprio provedor e o framework unifica seus filtros para você.

Quem possui um novo disco

Um filtro de linhas escopa leituras, atualizações e deleções, mas um criar não tem linha para filtrar. Assim, uma tabela com escopo para "linhas que eu possuo" ainda permitiria que um usuário crie uma linha pertencente a outra pessoa — ou a ninguém, que seu criador então não poderia ver. Declare a coluna que diz quem é o dono de um registro, e o framework o estabelece:

Pare-o com um filtro de linha na mesma coluna, assim os registros criados pelo usuário são os registros que ele pode ver. Para a propriedade que não é simplesmente o contato criador — a conta do criador, por exemplo — implemente ITableRecordOwnershipProvider e registre em AddTableRecordOwnershipProvider<T>(). Não defina um proprietário em um ITableRecordInterceptor instead: interceptors rodam antes das verificações de permissões, então o que eles definem é julgado como escrita do usuário.

O framework chama em cada criação daquela tabela, após as verificações de permissões, e define cada coluna Columns no que retorna — descartando qualquer coisa que a solicitação enviou e recusando uma atualização posterior que a alterasse, exatamente como para OwnedBy. Pare-o com um filtro de linha que corresponda ao que ele define, assim as pessoas sob as quais ele arquiva um registro são as que podem ver — aqui RowsMatchingAny(r => r.RowsOfTheirAccount("customerid"), r => r.RowsOwnedByContact("customerid")), com WithoutStamping() então o registro deixa a coluna para este provedor: dois que configuram uma coluna de forma diferente falham no salvamento.

Segurança em nível de coluna

A segurança das colunas é opt-in. Um provedor concede as colunas que pretende expor, e todo o resto — incluindo uma coluna que alguém adiciona à tabela no ano seguinte — permanece retido até ser nomeado. O id principal do registro é sempre legível, já que um registro que o framework não consegue identificar não serve para ninguém.

Leituras e escritas são conjuntos independentes: uma coluna pode ser legível, mas não gravável (o caso "mostrar o limite de créditos, não deixar que eles mudem"), ou ser gravável, mas não legível. Nomeie-as com Reading, Writing e ReadingAndWriting, ou desligue totalmente de uma dimensão com ReadingAllColumns / WritingAllColumns:

Nota

ReadingAllColumns() é algo que você precisa digitar deliberadamente. Ele não abre para qualquer coisa adicionada à tabela depois, o que é a negociação correta apenas quando a tabela é realmente pública — então o framework não assumirá isso em seu nome.

A escrita também pode diferir entre criar um registro e alterar um. Writing cobre ambos. WritingOnCreate permite que o usuário defina uma coluna ao criar o registro e o torne somente leitura a partir daí — a prioridade de um caso, escolhida quando é registrado. WritingOnUpdate é o inverso: alterável em um registro existente, não configurável no início. Ambos também tornam a coluna legível, como Writing, e ambos existem ativados TablePermissions para um provedor seu. Eles espelham as permissões separadas de criação e atualização concedidas pela segurança de campo do Dataverse:

O framework impõe o resultado em cada caminho que os dados cruzam a fronteira do servidor:

Nota

A coluna principal de id de uma tabela nunca é retida, seja lá o que o conjunto de leitura disser. O id é identidade, não dado — ele já está na URL que o chamador usou para acessar o registro — e chaves de linha, links de edição, relacionamentos de subgrade e exclusão todos se desfazem sem isso. Uma lista de permissão que nomeia as colunas que uma página precisa e esquece o id desmontaria o portal sem proteger nada.

Como os Componentes se Comportam

Os componentes do framework honram as permissões das colunas sozinhos — você não conecta nada. Uma coluna que o usuário não pode escrever é renderizada somente leitura e desativada onde quer que apareça: todo editor a pega por meio da resolução compartilhada de somente leitura, e a grade não dá à célula um editor inline, então ele volta ao texto de exibição simples. Um sistema fornecido readOnly="false" pelo consumidor não o substitui — o servidor rejeitaria o save de qualquer forma.

Uma coluna que o usuário pode não ler — uma mascarada — é renderizada em <ColumnDisplayValue> vez de um editor, em ambas as pilhas. Isso não é apenas uma gentileza: uma coluna mascarada não tem valor algum, apenas a máscara como seu valor formatado , então um editor vinculado a ela ficaria em branco; ColumnDisplayValue lê o valor formatado e assim mostra o marcador de lugar qual for o tipo da coluna. Colunas retidas por omissão nunca chegam a um componente — elas não estão no registro e os metadados da tabela não as listam.

O que o cliente recebe

Permissões de coluna vêm como um ColumnPermissions mapa — nome lógico de coluna para um ColumnSecurityPermission par de flags — para as colunas cujo acesso é restringido, o que Write significa que a coluna pode ser alterada em um registro existente. Qualquer coisa ausente tem acesso total, então uma tabela irrestrita não carrega nada. Um registro recuperado sozinho carrega o mapa; registros recuperados juntos compartilham um mapa, enviado uma vez na resposta, já que as permissões pertencem ao usuário e à tabela em vez de uma linha — os clientes de ambas as pilhas colocam isso de volta em cada registro, então ler as permissões de um registro funciona da mesma forma em ambos os casos. Respostas em grade também as reportam por coluna em ResolvedColumn.Permissions. Um registro sendo criado ainda não tem mapa próprio, então o endpoint de permissões de tabela também retorna NewRecordColumnPermissions — a mesma forma, julgada pelo que pode ser definido na criação — e ambas as RecordContext pilhas colocam isso em um novo registro para você. Colunas retidas por omissão estão deliberadamente ausentes de todos os mapas — omissão existe para que nada na resposta revele a coluna, e nomeá-la ali desfaria isso. Leia você mesmo através record.CanReadColumn(column) de / record.CanWriteColumn(column) em Blazor, ou os correspondentes canReadColumn / canWriteColumn ajudantes em @powerportalspro/core React.

Omissão ou Mascaramento

Por padrão, uma coluna retida é mascarada: o registro não carrega valor para ela e SecurityOptions.WithheldColumnMask (***** por padrão) como seu valor formatado, então um formulário ou grade ainda renderiza o campo e deixa claro que o valor está retido em vez de em branco. A máscara é a mesma independentemente de a coluna ter valor ou não, então ela também esconde isso. Defina SecurityOptions.WithheldColumnBehavior para Omit eliminar completamente a coluna do registro, como se a consulta nunca tivesse pedido, de modo que nada na resposta revela que a coluna existe — a escolha certa quando a própria existência da coluna é sensível. Reter uma coluna também retende qualquer coluna que a republique — o nome acompanhante de uma consulta, o gêmeo de moeda base de uma coluna de dinheiro — então uma lista de negação que nomeia uma coluna não pode ser contornada por outra. Uma única tabela pode sobrescrever a escolha do site em todo o local através TableColumnPermissions.WithheldColumnBehaviorde .

Nota

Pareie uma coluna mascarada com uma negação de escrita. Uma coluna mascarada não tem valor no registro, então um chamador que posta um registro carregado inteiro de volta não envia nada por ele — mas o framework aceita um payload salvo pelo valor nominal, então uma solicitação que define a coluna, incluindo a máscara, escreve sobre o valor armazenado se a coluna for gravável. A negação de escrita é o que a recusa.

Colunas que republicam outra coluna

Reter uma coluna também retém qualquer coluna que tenha o mesmo valor sob um segundo nome. O Dataverse cria para você: uma consulta …name e …yominame parceiros, o rótulo de uma escolha e um gêmeo de moeda base para cada coluna de moeda — creditlimit_base junto com creditlimit. São colunas comuns, então uma nomenclatura creditlimit de lista de negação não diz nada sobre creditlimit_base, e sem isso um valor mascarado voltaria diretamente por seu gêmeo. O link vem dos próprios metadados da plataforma, e não de uma regra de nomeação, então ele vale para suas próprias colunas também, e se aplica em leituras, em uma consulta que nomeia explicitamente o companheiro, em metadados de tabelas, em colunas de grade e em saves.

Boa prática — filtre na fonte

Um caso que o framework não consegue ver para você: uma coluna calculada ou rollup, e as colunas compostas da plataforma — fullname, yomifullname, address1_composite e seus irmãos. O Dataverse não informa quais colunas as alimentam, então reter lastname não fullnameretende , e uma coluna calculada sobre uma coluna que você negou ainda mostrará seu resultado. Nomei-as você mesmo no conjunto de leitura quando suas entradas forem sensíveis. Uma lista de permissões (ColumnPermissions.Allow(…)) evita o problema completamente, já que nada é legível até que você a nomeie — que é o padrão melhor para uma tabela contendo qualquer coisa que valha a pena reter.

Nota

Quando vários provedores cobrem uma tabela, seus conjuntos de colunas compõem da mesma forma que suas operações: aditivamente entre papéis, e sob MultiplePermissionHandlersBehavior dentro de um mesmo grupo. Um provedor que existe apenas para escopar linhas e não diz nada sobre colunas é completamente deixado de fora da dobra da coluna, então ele não amplia nem restringe o que os outros concederam.

Dataverse-Native Security (Prévia)

O modelo de segurança recomendado para o futuro permite que o próprio Dataverse impeça segurança para os usuários do seu portal, baseado no recurso unificado de segurança do Dataverse do Power Pages. Em vez de escrever manipuladores de permissões em código, você gerencia o acesso com funções web e permissões de tabela do Power Pages, que a plataforma transforma em papéis de segurança do Dataverse que o Dataverse aplica em cada solicitação. O modelo está atualmente em prévia — tanto o recurso da Microsoft quanto o suporte do Power Portals Pro — e o Power Portals Pro seguirá o cronograma de lançamentos da Microsoft até a disponibilidade geral.

Quando ativado, o PowerPortalsPro fornece automaticamente um sistema gerenciado (C2) systemuser para cada contato do portal — no registro para novos contatos e preguiçosamente no login para os existentes — junto com o powerpagesusermapping registro que liga o contato, o usuário do sistema e seu site Power Pages. Cada chamada Dataverse para a sessão então se passa por esse usuário do sistema, então os papéis de segurança que o Power Pages sincroniza a partir dos seus papéis web e permissões de tabela governam exatamente o que o usuário pode ver e fazer. A sessão carrega um PortalUserType de ContactStubUser para que sua interface possa sempre distinguir esses usuários provisionados dos usuários internos reais.

Nota

Para usar esse modelo de segurança, você deve criar um site Power Pages no seu ambiente Dataverse — é isso que instala os componentes do framework Microsoft e permite habilitar o recurso de segurança unificada. Você não precisa de um plano pago do Power Pages, e pode deletar o site imediatamente após instalar e ativar o recurso. O registro do site do Power Pages (powerpagesite) referenciado PowerPagesSiteId por deve existir no ambiente, já que os mapeamentos do usuário e a sincronização de papéis de segurança são resolvidos contra ele.

Ativando a Segurança Dataverse-Native

Ative o modelo no SecurityOptions Program.csseu servidor, fornecendo o ID do seu registro do site Power Pages:

A configuração é validada na inicialização da aplicação: quando ProvisionSystemUsers ativada, PowerPagesSiteId deve ser definida e resolvida para um registro existente powerpagesite , caso contrário a aplicação não inicia com a orientação.

Conceda acesso exatamente como o Power Pages: configure papéis web e permissões de tabelas — no app Power Pages Management, ou na página Web Roles do seu portal da solução Power Portals Pro Enhanced Authorization — e atribua funções web aos contatos (através do app de Gerenciamento, programaticamente ou automaticamente para novos usuários com regras naquela mesma página). A plataforma sincroniza esses papéis em papéis de segurança gerados automaticamente (nomeados PowerPages_*) e os atribui automaticamente conforme mudanças de associação a papéis web — como a configuração está inteiramente no Power Pages, seu portal pode se mover para ou de um site real do Power Pages sem atritos. Note que mudanças de papéis e privilégios podem levar de alguns segundos a alguns minutos para se propagar pelos caches do Dataverse antes de entrarem em vigor.

Siga o guia passo a passo de configuração

Associando um Login Externo a um Contato

Quando alguém faz login com a Microsoft, Google ou outro provedor externo, o portal precisa descobrir a qual contato existente — se houver — esse login pertence. Ele resolve isso em duas etapas:

  1. Um link existente. Se a conta já fez login antes, uma adx_externalidentity linha já a vincula a um contato. Essa é uma declaração explícita e armazenada "esta conta é esta pessoa", então ela sempre vence e nunca é afetada pelas configurações abaixo.
  2. O recurso de e-mail alternativo. Ainda sem link, o portal corresponde ao endereço de e-mail fornecido pelo provedor com as colunas do contato. Essa é a etapa que você pode configurar — e a etapa que decide se um cliente retornado entra no contato atual ou recebe uma duplicata.

Por padrão, duas colunas são pesquisadas, primeiro nome de usuário do portal. Contatos criados pelo portal carregam adx_identity_username, enquanto os contatos importados ou digitados pela equipe geralmente têm apenas emailaddress1 — pesquisar ambos é o que permite que um cliente existente faça login e fique em seu próprio registro, em vez de um novo:

A ordem importa: é a precedência, não apenas uma lista. As colunas são pesquisadas juntas em uma única consulta, e a primeira coluna da sua lista que corresponde a qualquer coisa decide o vencedor — então, se um contato tem o endereço como nome de usuário do portal e outro o mantiver em emailaddress1, a correspondência de nome de usuário vence na ordem padrão.

Liste menos colunas para o restrito de correspondência: [ContactEmailColumn.IdentityUsername] restringe a contas criadas pelo portal, e uma lista vazia desativa completamente o recurso de e-mail, deixando um link de identidade externa existente como a única forma de uma conta resolver para um contato. Adicione ContactEmailColumn.EmailAddress2 e ContactEmailColumn.EmailAddress3 amplie — elas são deixadas de fora do padrão deliberadamente, pelo motivo abaixo.

Boa prática — filtre na fonte

Cada coluna que você lista é uma forma de que quem controla um endereço de e-mail seja reconhecido como o contato que o detém. Liste apenas colunas que seu processo de entrada de dados trate como pertencentes ao próprio contato — se emailaddress2 for onde sua equipe arquiva o endereço de um assistente ou uma caixa de entrada compartilhada da empresa, listá-la permite que quem ler essa caixa de entrada entre como esse contato.

Boa prática — filtre na fonte

A correspondência faz do endereço de e-mail um identificador, não apenas um rótulo — ele decide qual contato existente um login se torna. Assim, o portal só pula o e-mail de confirmação quando o provedor de identidade realmente verificou exatamente esse endereço. Se o endereço foi digitado sobre o fornecido pelo provedor, ou o provedor nunca verificou, um link de confirmação é enviado e o login externo não é associado ao contato até que esse link seja seguido.

Quais logins contam como verificados não são propriedade do provedor. O Google verifica todos os endereços que ele afirma. A Microsoft não: uma conta pessoal da Microsoft verificou seu endereço, mas uma conta de trabalho ou escola do Entra fornece o que estiver no atributo do mail diretório, que um administrador de locatário pode definir para qualquer valor em qualquer domínio — incluindo um domínio que seu inquilino não possui. O portal lê o token do provedor, em vez disso: uma conta pessoal é verificada, e uma conta de trabalho ou escola é verificada apenas quando o Entra garante exatamente aquele endereço — sua verified_primary_email ou verified_secondary_email reivindicação o lista, ou xms_edov diz que seu domínio pertence ao próprio locatário do usuário. O Entra envia essas reivindicações apenas quando o registro do aplicativo as solicita (veja Configuração de Login do ID do Entra); sem elas, os logins no trabalho e na escola confirmam por e-mail na primeira vez.

Nota

Essas configurações se aplicam apenas ao login externo. O login, registro e redefinição de senha locais, continuam a coincidir adx_identity_username sozinhos, deliberadamente — o fluxo de redefinição de senha envia seu link para o endereço inserido, então combinar colunas secundárias de e-mail ali permitiria que alguém redefinisse a senha de outra pessoa.

Permitindo apenas que contatos existentes façam login

Por padrão, qualquer pessoa pode se tornar um usuário do portal: registrar-se ou fazer login com um provedor externo sob um endereço que nenhum contato possui, cria um contato. Quando o portal é para pessoas que você já possui no Dataverse — clientes, membros, parceiros — desative o cadastro, e somente eles podem fazer login:

A página de registro e seus links desaparecem, e o servidor se recusa a criar um usuário conforme solicitado. Um login externo ainda encontra seu contato conforme descrito acima e faz links para ele; um que não corresponde a ninguém é recusado em vez de criar um contato. Contas locais não são afetadas para quem já tem um.

Nota

Um login recusado só é explicado na tela quando o provedor verificou exatamente esse endereço, porque então a pessoa que faz login já provou que é a proprietária. Para qualquer outro endereço, o portal responde exatamente como para um endereço que tem um contato — "verifique seu e-mail" — e envia o endereço com um aviso curto informando que não está registrado. Avisar diretamente o visitante permitiria que qualquer pessoa digitasse endereços no formulário para descobrir quem tem uma conta.

O aviso é enviado pelo próprio remetente de e-mail do portal. Um host que o substitua por sua própria pilha de e-mails também deve registrar um ISignUpRefusalEmailSender; sem um, a recusa é registrada e nenhum aviso é enviado.

Classes Base Integradas

A estrutura fornece classes base para simplificar padrões comuns de segurança:

Referência API

AuthorizePortalRoleAttribute Classe

Propriedades

Nome
Tipo
Padrão
Descrição
AuthenticationSchemesstring?
Policystring?
RoleNamesIReadOnlyList<string>
Os nomes dos papéis que esse atributo exige, qualquer um dos quais o satisfaz.
Rolesstring?
TypeIdObject
Nome: AuthenticationSchemes
Tipo: string?
Nome: Policy
Tipo: string?
Nome: RoleNames
Tipo: IReadOnlyList<string>
Descrição: Os nomes dos papéis que esse atributo exige, qualquer um dos quais o satisfaz.
Nome: Roles
Tipo: string?
Nome: TypeId
Tipo: Object

Métodos

Nome
Parâmetros
Tipo
Descrição
IsDefaultAttributebool
MatchObject obj
bool
Nome: IsDefaultAttribute
Tipo: bool
Nome: Match
Parâmetros: Object obj
Tipo: bool

ITablePermissionProvider Interface

Propriedades

Nome
Tipo
Padrão
Descrição
Tablestring
Nome lógico da tabela à qual esse provedor se aplica. Correspondeu exatamente, então deve ser o Nome lógico do Dataverse em minúsculas.
Nome: Table
Tipo: string
Descrição: Nome lógico da tabela à qual esse provedor se aplica. Correspondeu exatamente, então deve ser o Nome lógico do Dataverse em minúsculas.

Métodos

Nome
Parâmetros
Tipo
Descrição
GetPermissionsAsyncUserInfo user
Task<TablePermissions>
O que user pode fazer com esta tabela e quais de suas colunas podem ser lidas e escrever. Retorno TablePermissions.None para um usuário que não deveria ter acesso. As operações são um portão em nível de tabela, não um filtro de linha: conceder TableSecurityPermission.Read se o usuário puder ver alguma das tabelas linhas e escopo quais estão em Services.TableQueryContext). Colunas são opt-in. Nada é legível ou gravável até que seja nomeado — concedendo TableSecurityPermission.Read Sozinho expõe apenas o ID do registro. Use Reading(System.String[]) e Writing(System.String[]) nomeá-los, ou TablePermissions.AllColumns para optar por não usar a segurança de colunas para esta tabela. Um provedor que existe apenas para definir linhas pode deixar as colunas intactas — sem falar sobre eles e não compõe opinião, nem ampliando nem estreitando o que o outro Provedores na mesa concedidos. Dizer nada ainda é falha-fechado no geral: quando não O provedor nomeia uma coluna, nenhuma é legível. Chamada uma vez por tabela por usuário e armazenada em cache para a solicitação, então pode ser tão caro quanto precisa ser.
GetQueryFilterAsyncTableQueryContext context
Task<TableQueryFilter>
Escopos sobre quais linhas dessa tabela o usuário pode agir: um filtro construído com Query.LogicalOperator), TableQueryFilter.AllRows para todo reme conforme as operações permitirem, ou nullsem linhas. As linhas falham ao fechar. O provedor precisa dizer quais linhas concede, da mesma forma que precisa Nomeie as colunas: null — ou um filtro sem condições — não concede nenhuma, então Esquecer de colocar o escopo de uma tabela nega isso em vez de publicar todas as linhas. Por exemplo, TableQueryFilter.AllRows Quando cada briga é o que você quer dizer. O filtro é adicionado à consulta antes da execução do Dataverse, então as linhas que o usuário pode não ver são nunca buscado. Aplica-se a toda consulta que o portal emite para a tabela: grades, consultas, subgrades, gráficos e cargas de registro único, além da busca pré-voo antes de uma atualização ou um delete — que é o que TableQueryContext.Operation distingue. Também executa sob ambos os modelos de segurança, então permanece em vigor quando a segurança nativa do Dataverse Ignora Services.UserInfo). O framework decide como os filtros se combinam, não o provedor. Filtros dos provedores No mesmo grupo intersectam — dois provedores em um mesmo papel devem concordar. Filtros de diferentes papéis são sindicatos, então ocupar outro cargo amplia o que você vê, combinando com o As operações compor. Definir PortalRoleOptions.CompositionBehavior para RoleCompositionBehavior.Restrictive para cruzar papéis também. Dentro de um grupo, um provedor que null responde não deixa linhas no grupo, e TableQueryFilter.AllRows deixa os filtros dos outros provedores decidir. De lado para o outro lado grupos, um grupo concede TableQueryFilter.AllRows amplia o aditivo padrão união a cada linha — então o filtro de um papel só significa algo quando os outros grupos concedem Esse filtro de mesa também.
Nome: GetPermissionsAsync
Parâmetros: UserInfo user
Tipo: Task<TablePermissions>
Descrição: O que user pode fazer com esta tabela e quais de suas colunas podem ser lidas e escrever. Retorno TablePermissions.None para um usuário que não deveria ter acesso. As operações são um portão em nível de tabela, não um filtro de linha: conceder TableSecurityPermission.Read se o usuário puder ver alguma das tabelas linhas e escopo quais estão em Services.TableQueryContext). Colunas são opt-in. Nada é legível ou gravável até que seja nomeado — concedendo TableSecurityPermission.Read Sozinho expõe apenas o ID do registro. Use Reading(System.String[]) e Writing(System.String[]) nomeá-los, ou TablePermissions.AllColumns para optar por não usar a segurança de colunas para esta tabela. Um provedor que existe apenas para definir linhas pode deixar as colunas intactas — sem falar sobre eles e não compõe opinião, nem ampliando nem estreitando o que o outro Provedores na mesa concedidos. Dizer nada ainda é falha-fechado no geral: quando não O provedor nomeia uma coluna, nenhuma é legível. Chamada uma vez por tabela por usuário e armazenada em cache para a solicitação, então pode ser tão caro quanto precisa ser.
Nome: GetQueryFilterAsync
Parâmetros: TableQueryContext context
Tipo: Task<TableQueryFilter>
Descrição: Escopos sobre quais linhas dessa tabela o usuário pode agir: um filtro construído com Query.LogicalOperator), TableQueryFilter.AllRows para todo reme conforme as operações permitirem, ou nullsem linhas. As linhas falham ao fechar. O provedor precisa dizer quais linhas concede, da mesma forma que precisa Nomeie as colunas: null — ou um filtro sem condições — não concede nenhuma, então Esquecer de colocar o escopo de uma tabela nega isso em vez de publicar todas as linhas. Por exemplo, TableQueryFilter.AllRows Quando cada briga é o que você quer dizer. O filtro é adicionado à consulta antes da execução do Dataverse, então as linhas que o usuário pode não ver são nunca buscado. Aplica-se a toda consulta que o portal emite para a tabela: grades, consultas, subgrades, gráficos e cargas de registro único, além da busca pré-voo antes de uma atualização ou um delete — que é o que TableQueryContext.Operation distingue. Também executa sob ambos os modelos de segurança, então permanece em vigor quando a segurança nativa do Dataverse Ignora Services.UserInfo). O framework decide como os filtros se combinam, não o provedor. Filtros dos provedores No mesmo grupo intersectam — dois provedores em um mesmo papel devem concordar. Filtros de diferentes papéis são sindicatos, então ocupar outro cargo amplia o que você vê, combinando com o As operações compor. Definir PortalRoleOptions.CompositionBehavior para RoleCompositionBehavior.Restrictive para cruzar papéis também. Dentro de um grupo, um provedor que null responde não deixa linhas no grupo, e TableQueryFilter.AllRows deixa os filtros dos outros provedores decidir. De lado para o outro lado grupos, um grupo concede TableQueryFilter.AllRows amplia o aditivo padrão união a cada linha — então o filtro de um papel só significa algo quando os outros grupos concedem Esse filtro de mesa também.

TablePermissions Classe

Propriedades

Nome
Tipo
Padrão
Descrição
ColumnsTableColumnPermissions
As colunas que o usuário pode ler e escrever. TableColumnPermissions.None a menos que Algo chamado eles: Acesso a colunas é concedido, nunca assumido.
OperationsTableSecurityPermission
As operações que o usuário pode realizar na tabela são um valor de flags. Isso é um nível de tabela gate, não um filtro de linha — inclua TableSecurityPermission.Read se o usuário puder veja qualquer uma das linhas da tabela e faça o escopo de quais passam por Services.TableQueryContext).
Nome: Columns
Tipo: TableColumnPermissions
Descrição: As colunas que o usuário pode ler e escrever. TableColumnPermissions.None a menos que Algo chamado eles: Acesso a colunas é concedido, nunca assumido.
Nome: Operations
Tipo: TableSecurityPermission
Descrição: As operações que o usuário pode realizar na tabela são um valor de flags. Isso é um nível de tabela gate, não um filtro de linha — inclua TableSecurityPermission.Read se o usuário puder veja qualquer uma das linhas da tabela e faça o escopo de quais passam por Services.TableQueryContext).

Métodos

Nome
Parâmetros
Tipo
Descrição
AllColumnsTablePermissions
Opta por não participar totalmente da segurança em nível de coluna — toda coluna legível e gravável. O Comportamento pré-segurança na coluna, detalhado em vez de herdado.
AllowTableSecurityPermission operations
TablePermissions
Isso acrescenta operations ao que esse valor já concede.
AllowingTableSecurityPermission operations
TablePermissions
Concessões operations e sem colunas. Corrente Reading(System.String[]), Writing(System.String[]) Ou TablePermissions.ReadingAllColumns para abrir colunas para cima.
Readingstring[] columns
TablePermissions
Permite a leitura das colunas nomeadas, além de qualquer já permitida. Indistinto a maiúsculas minúsculas, Então a grafia do portal do criador funciona tão bem quanto o nome lógico.
ReadingAllColumnsTablePermissions
Opta por não usar segurança de leitura em nível de coluna para esta tabela: todas as colunas, incluindo as adicionadas para a mesa depois. Deliberadamente explícito — o arcabouço não vai assumir isso.
ReadingAllColumnsExceptstring[] columns
TablePermissions
Opta por não usar segurança de leitura em nível de coluna, exceto para as colunas nomeadas — todas as colunas, exceto Essas, incluindo as adicionadas depois. Não abre para nada novo, então prefiro Reading(System.String[]) em tabelas que contêm dados sensíveis.
ReadingAndWritingstring[] columns
TablePermissions
Permite tanto a leitura quanto a escrita das colunas nomeadas.
WithColumnsTableColumnPermissions columns
TablePermissions
Substitui as regras da coluna no atacado, para um provedor que prefere construir um Services.TableColumnPermissions ela mesma que encadear os métodos fluentes.
WithholdingWithheldColumnBehavior behavior
TablePermissions
Como as colunas retidas dessa tabela voltam — omitidas, ou apresentam um valor mascarado. Anula o site para SecurityOptions.WithheldColumnBehavior toda a tabela desta tabela.
Writingstring[] columns
TablePermissions
Permite escrever as colunas nomeadas — quando um registro é criado e quando ele é atualizado — em além de qualquer que já seja permitido. Escrever uma coluna não implica lê-la — nomei-a Reading(System.String[]) também se o usuário deve ver o que escreveu.
WritingAllColumnsTablePermissions
Opta por não usar segurança de escrita em nível de coluna para esta tabela: o usuário pode escrever qualquer coluna, ao criar e ao atualizar. Substitui ambos os conjuntos de escrita, então chame WritingOnCreate(System.String[]) / WritingOnUpdate(System.String[]) Depois disso, não antes.
WritingAllColumnsExceptstring[] columns
TablePermissions
Opta por não usar segurança de escrita em nível de coluna, exceto nas colunas nomeadas, que permanecem somente leitura. Substitui ambos os conjuntos de escrita, então chame WritingOnCreate(System.String[]) / WritingOnUpdate(System.String[]) Depois disso, não antes.
WritingOnCreatestring[] columns
TablePermissions
Permite definir as colunas nomeadas quando um registro é criado, e somente então: uma vez que ele exista Eles são somente leitura, mesmo que uma chamada anterior — Writing(System.String[]), TablePermissions.WritingAllColumns — os tornava escritos. A prioridade de um caso, escolhido quando é registrado e corrigido a partir daí. Chame após qualquer WritingAllColumn..., que substitui Ambos escrevem conjuntos. Como Writing(System.String[]), não implica leitura.
WritingOnUpdatestring[] columns
TablePermissions
Permite alterar as colunas nomeadas em um registro existente, mas não defini-las quando está criados, mesmo que uma chamada anterior os tornasse graváveis — notas de resolução que só significam algo quando o caso existir. Chame de WritingAllColumn..., que substitui Ambos escrevem conjuntos. Como Writing(System.String[]), não implica leitura.
Nome: AllColumns
Tipo: TablePermissions
Descrição: Opta por não participar totalmente da segurança em nível de coluna — toda coluna legível e gravável. O Comportamento pré-segurança na coluna, detalhado em vez de herdado.
Nome: Allow
Parâmetros: TableSecurityPermission operations
Tipo: TablePermissions
Descrição: Isso acrescenta operations ao que esse valor já concede.
Nome: Allowing
Parâmetros: TableSecurityPermission operations
Tipo: TablePermissions
Descrição: Concessões operations e sem colunas. Corrente Reading(System.String[]), Writing(System.String[]) Ou TablePermissions.ReadingAllColumns para abrir colunas para cima.
Nome: Reading
Parâmetros: string[] columns
Tipo: TablePermissions
Descrição: Permite a leitura das colunas nomeadas, além de qualquer já permitida. Indistinto a maiúsculas minúsculas, Então a grafia do portal do criador funciona tão bem quanto o nome lógico.
Nome: ReadingAllColumns
Tipo: TablePermissions
Descrição: Opta por não usar segurança de leitura em nível de coluna para esta tabela: todas as colunas, incluindo as adicionadas para a mesa depois. Deliberadamente explícito — o arcabouço não vai assumir isso.
Nome: ReadingAllColumnsExcept
Parâmetros: string[] columns
Tipo: TablePermissions
Descrição: Opta por não usar segurança de leitura em nível de coluna, exceto para as colunas nomeadas — todas as colunas, exceto Essas, incluindo as adicionadas depois. Não abre para nada novo, então prefiro Reading(System.String[]) em tabelas que contêm dados sensíveis.
Nome: ReadingAndWriting
Parâmetros: string[] columns
Tipo: TablePermissions
Descrição: Permite tanto a leitura quanto a escrita das colunas nomeadas.
Nome: WithColumns
Parâmetros: TableColumnPermissions columns
Tipo: TablePermissions
Descrição: Substitui as regras da coluna no atacado, para um provedor que prefere construir um Services.TableColumnPermissions ela mesma que encadear os métodos fluentes.
Nome: Withholding
Parâmetros: WithheldColumnBehavior behavior
Tipo: TablePermissions
Descrição: Como as colunas retidas dessa tabela voltam — omitidas, ou apresentam um valor mascarado. Anula o site para SecurityOptions.WithheldColumnBehavior toda a tabela desta tabela.
Nome: Writing
Parâmetros: string[] columns
Tipo: TablePermissions
Descrição: Permite escrever as colunas nomeadas — quando um registro é criado e quando ele é atualizado — em além de qualquer que já seja permitido. Escrever uma coluna não implica lê-la — nomei-a Reading(System.String[]) também se o usuário deve ver o que escreveu.
Nome: WritingAllColumns
Tipo: TablePermissions
Descrição: Opta por não usar segurança de escrita em nível de coluna para esta tabela: o usuário pode escrever qualquer coluna, ao criar e ao atualizar. Substitui ambos os conjuntos de escrita, então chame WritingOnCreate(System.String[]) / WritingOnUpdate(System.String[]) Depois disso, não antes.
Nome: WritingAllColumnsExcept
Parâmetros: string[] columns
Tipo: TablePermissions
Descrição: Opta por não usar segurança de escrita em nível de coluna, exceto nas colunas nomeadas, que permanecem somente leitura. Substitui ambos os conjuntos de escrita, então chame WritingOnCreate(System.String[]) / WritingOnUpdate(System.String[]) Depois disso, não antes.
Nome: WritingOnCreate
Parâmetros: string[] columns
Tipo: TablePermissions
Descrição: Permite definir as colunas nomeadas quando um registro é criado, e somente então: uma vez que ele exista Eles são somente leitura, mesmo que uma chamada anterior — Writing(System.String[]), TablePermissions.WritingAllColumns — os tornava escritos. A prioridade de um caso, escolhido quando é registrado e corrigido a partir daí. Chame após qualquer WritingAllColumn..., que substitui Ambos escrevem conjuntos. Como Writing(System.String[]), não implica leitura.
Nome: WritingOnUpdate
Parâmetros: string[] columns
Tipo: TablePermissions
Descrição: Permite alterar as colunas nomeadas em um registro existente, mas não defini-las quando está criados, mesmo que uma chamada anterior os tornasse graváveis — notas de resolução que só significam algo quando o caso existir. Chame de WritingAllColumn..., que substitui Ambos escrevem conjuntos. Como Writing(System.String[]), não implica leitura.

AuthClientOptions Classe

Propriedades

Nome
Tipo
Padrão
Descrição
LocalAccountsEnabledbool
True
Se o portal aceita contas locais de usuário/senha. Padrão verdadeiro. Defina como false para um portal interno apenas (login apenas Microsoft/Entra). Isso desliga as contas locais no servidor, não apenas na interface. MapAuthEndpoints não mapeia login de senha, registro, redefinição de senha, configuração ou alteração de um ou gerenciamento de dois fatores, então essas rotas 404. A camada de Identidade do portal também recusa o login por senha e se recusa a criar, adicionar, alterar ou redefinir uma senha, que também cobre páginas de contas renderizadas pelo servidor. Faça login por meio de provedores externos, confirmação por e-mail, perfis, gerenciamento de login externo, download de dados pessoais e Exclusão de contas não é afetada. Os clientes leem para esconder o formulário de login local e as páginas de registro/redefinição de senha. Senhas já armazenadas para contas existentes permanecem no Dataverse, mas não podem mais ser Costumava fazer login.
SignUpEnabledbool
True
Se fazer login pode criar um usuário do portal. Padrão verdadeiro: qualquer pessoa que se cadastrar, ou Faz login por meio de um provedor externo com endereço que nenhum contato possui, recebe um novo contato. Defina como falso para que apenas pessoas que já têm contato possam entrar. Com ele desligado, um login externo ainda corresponde a um contato existente — por um link anterior, ou pelas colunas de e-mail em SecurityOptions.ContactMatching — e links para ele, enviando um Confirmação primeiro quando o provedor não garantiu o endereço. Um login que ninguém corresponde é recusado em vez de criar um contato. A pessoa que faz login só é informada quando o o provedor verificou o endereço; caso contrário, o endereço recebe um aviso pelo correio e o login é respondido como um que correspondia, então o formulário não pode ser usado para descobrir quais endereços possuem um contato. MapAuthEndpoints não mapeia o registro, então que a rota 404s, e o a camada de Identidade do portal se recusa a criar qualquer usuário, o que cobre conta renderizada pelo servidor Páginas também. Os clientes leem para esconder a página do registro e o link, além de explicar a recusa de registro.
Nome: LocalAccountsEnabled
Tipo: bool
Padrão: True
Descrição: Se o portal aceita contas locais de usuário/senha. Padrão verdadeiro. Defina como false para um portal interno apenas (login apenas Microsoft/Entra). Isso desliga as contas locais no servidor, não apenas na interface. MapAuthEndpoints não mapeia login de senha, registro, redefinição de senha, configuração ou alteração de um ou gerenciamento de dois fatores, então essas rotas 404. A camada de Identidade do portal também recusa o login por senha e se recusa a criar, adicionar, alterar ou redefinir uma senha, que também cobre páginas de contas renderizadas pelo servidor. Faça login por meio de provedores externos, confirmação por e-mail, perfis, gerenciamento de login externo, download de dados pessoais e Exclusão de contas não é afetada. Os clientes leem para esconder o formulário de login local e as páginas de registro/redefinição de senha. Senhas já armazenadas para contas existentes permanecem no Dataverse, mas não podem mais ser Costumava fazer login.
Nome: SignUpEnabled
Tipo: bool
Padrão: True
Descrição: Se fazer login pode criar um usuário do portal. Padrão verdadeiro: qualquer pessoa que se cadastrar, ou Faz login por meio de um provedor externo com endereço que nenhum contato possui, recebe um novo contato. Defina como falso para que apenas pessoas que já têm contato possam entrar. Com ele desligado, um login externo ainda corresponde a um contato existente — por um link anterior, ou pelas colunas de e-mail em SecurityOptions.ContactMatching — e links para ele, enviando um Confirmação primeiro quando o provedor não garantiu o endereço. Um login que ninguém corresponde é recusado em vez de criar um contato. A pessoa que faz login só é informada quando o o provedor verificou o endereço; caso contrário, o endereço recebe um aviso pelo correio e o login é respondido como um que correspondia, então o formulário não pode ser usado para descobrir quais endereços possuem um contato. MapAuthEndpoints não mapeia o registro, então que a rota 404s, e o a camada de Identidade do portal se recusa a criar qualquer usuário, o que cobre conta renderizada pelo servidor Páginas também. Os clientes leem para esconder a página do registro e o link, além de explicar a recusa de registro.