Esta página ainda não foi traduzida: mostrando a versão em inglês.
Access & Roles
Os papéis são compostos, nunca fixos no código. Permissões atômicas se combinam em papéis; os papéis controlam o acesso aos dados até a linha e a coluna e decidem quais interfaces de módulo um build chega a ver. Isso substitui a divisão entre chave de cliente e chave de servidor: a credencial aponta para uma identidade, e os papéis dela são resolvidos a cada requisição.
Quando usar
- Você precisa de uma credencial mais restrita que “cliente” ou “servidor”: por trás dela, papéis (role) compostos são resolvidos a cada requisição.
- O acesso aos dados precisa parar em linhas e colunas: escopo por região, máscaras para dados pessoais, prestadores de serviço com acesso somente leitura.
- Um build só deve ver as interfaces que o papel dele libera: para um visitante, expulsar e fechar simplesmente não existem.
- A sua UI precisa desabilitar botões com precisão:
CanIavalia a mesma política que o servidor vai aplicar. - Dispensável quando os presets que vêm com a plataforma (
player,room-owner,seller, …) já correspondem aos seus atores. Todo módulo os respeita por padrão; o catálogo completo está em Conceitos principais.
Quem faz o quê
| Ator | O que faz nesta página |
|---|---|
operator | declara papéis e políticas, define limites por linha e por coluna, concede papéis, emite chaves |
match-organizer | equipe do torneio: tem uma chave com papéis compostos, controla as inscrições, não pode fazer reembolsos |
todo ator | verifica CanI antes de agir; vê só as interfaces que tem liberadas |
Resumo
entry-validator com limites por linha e por coluna, conceda o papel e verifique CanI antes de agir[Role("entry-validator")]
public class EntryValidator
{
[Allow(Rooms.Membership.Administer)] public Permit GateEntries;
[Allow(Data.Records.Read, table: "player_profile", rows: "banned == false",
columns: "id, display_name")] public Permit SeeProfiles;
}
await PlayServ.Access.Grant(staffId, Roles.EntryValidator, Roles.MatchOrganizer);
var key = await PlayServ.Access.IssueKey(staffId); // the credential names no roles
// any actor, before attempting an operation:
if (await PlayServ.Access.CanI(Commerce.Orders.Administer)) Hud.ShowRefund();@Role('entry-validator')
export class EntryValidator {
@Allow(Rooms.membership.administer) gateEntries: Permit;
@Allow(Data.records.read, { table: 'player_profile', rows: 'banned == false',
columns: ['id', 'display_name'] }) seeProfiles: Permit;
}
await playserv.access.grant(staffId, Roles.entryValidator, Roles.matchOrganizer);
const key = await playserv.access.issueKey(staffId); // the credential names no roles
// any actor, before attempting an operation:
if (await playserv.access.canI(Commerce.orders.administer)) hud.showRefund();@role("entry-validator")
class EntryValidator:
gate_entries = allow(rooms.membership.administer)
see_profiles = allow(data.records.read, table="player_profile",
rows="banned == false", columns=["id", "display_name"])
await playserv.access.grant(staff_id, roles.ENTRY_VALIDATOR, roles.MATCH_ORGANIZER)
key = await playserv.access.issue_key(staff_id) # the credential names no roles
# any actor, before attempting an operation:
if await playserv.access.can_i(commerce.orders.administer):
hud.show_refund()Ainda não está decidido como declarar com atributos em Go (O-1). Os exemplos chegam quando a forma de escrita for escolhida.
// declarations compile into the same pushed model — playserv push from the UE project or CI
USTRUCT(PSRole = "entry-validator")
struct FEntryValidator
{
GENERATED_BODY()
UPROPERTY(PSAllow = (Atom = "Rooms.Membership.Administer"))
FPSPermit GateEntries;
UPROPERTY(PSAllow = (Atom = "Data.Records.Read", Table = "player_profile",
Rows = "banned == false", Columns = "id, display_name"))
FPSPermit SeeProfiles;
};
// granting is an operator act; a build checks what its identity resolves to
const FPSActor Me = Client->Whoami(); // which interfaces this actor unlocks
Client->Access->CanI(TEXT("Commerce.Orders.Administer"),
TPSOnResult<bool>::CreateWeakLambda(this, [this](const TPSResult<bool>& Result)
{
if (!Result.HasValue()) { return; }
if (Result.Value()) { Hud->ShowRefund(); }
}));
// co_await support ships later: a built-in SDK coroutine wrapper that respects Unreal's GC and threading.// the same `[Role]` / `[Allow]` declaration as the server tab, on the Unity 2021.3 runtime
var me = playserv.Whoami(); // which interfaces this actor unlocks
if (await playserv.Access.CanI(Commerce.Orders.Administer)) hud.ShowRefund();Uma permissão atômica é um par: um recurso e um de quatro verbos — read, write, execute, administer. O conjunto de verbos é fixo; um caso que não se encaixa nele divide o recurso em vez de aumentar a lista. Por isso, controlar a entrada de outra pessoa é Rooms.Membership.Administer, e não um verbo ValidateEntry só para isso: agir sobre a participação de outro ator é administração, enquanto entrar você mesmo é Rooms.Membership.Write no mesmo recurso.
O modelo
O ACL de dados é papel × operação × predicado de linhas × máscara de campos — um único modelo, idêntico seja ele escrito no código, pela API ou na grade de papéis do painel.
Do que o acesso é feito.
| Termo | O que é |
|---|---|
permissão atômica | um par recurso × verbo. Os quatro verbos são read (buscar, selecionar, assinar), write (criar, alterar, excluir e agir por si mesmo — entrar, sair), execute (chamar uma função, aplicar uma habilidade) e administer (agir sobre os outros: expulsar, fechar, forçar uma mudança de estado) |
papel | um conjunto nomeado de permissões atômicas. Pode incluir outro papel |
preset de papel | vem com a plataforma, construído sobre permissões atômicas, e continua funcionando sem mudanças para quem já o usa em produção. É um ponto de partida, não uma restrição: um projeto declara papéis próprios com as mesmas permissões atômicas |
predicado de linhas | quais linhas — um predicado booleano sobre valores da sessão |
máscara de campos | quais campos, declarada por papel e por operação |
O que cada credencial libera.
| Credencial | O que libera |
|---|---|
chave de jogador | vai dentro de um build da engine; o jogador por trás dela chega com o login, e o build vê as linhas cl de toda tabela de operações |
chave de host | fica com um servidor dedicado ou um cliente mestre (master-client), e os papéis dela liberam as linhas mc |
código publicado | roda com o papel backend-service do projeto — é isso que o Authoritative = true de um ranking verifica |
um hook registrado | não concede nada a mais: a sua função mantém o papel com que foi publicada |
A legenda das tags (fn / cl / mc / adm) fica em Conceitos principais.
O que vale para toda verificação.
| Sempre | O que é |
|---|---|
uma credencial | não carrega lista de papéis: aponta para uma identidade, e os papéis são resolvidos no servidor a cada requisição. Uma revogação invalida na hora a resolução em cache, sem esperar o limite de desatualização declarado |
a delegação | muda o escopo, nunca a capacidade: agir em nome de um jogador muda quais linhas ficam visíveis e a quem uma escrita é atribuída, mas não concede nenhuma operação que o ator já não tivesse |
o verbo | responde que tipo de efeito, e o predicado responde quais linhas. Se dois casos diferem só em de quem é a linha, é um predicado; se o próprio efeito é outro, é outra operação e talvez outro verbo — por isso “expulsar” é administer, e não write com um predicado amplo |
um dono | sempre vê a si mesmo, diga o predicado o que disser |
a visibilidade | não é segurança — uma otimização de canais e uma permissão são mecanismos diferentes, e nenhum substitui o outro |
um módulo desativado | não tem interface: estar ativado é uma propriedade do build, então a geração de código não emite nada para um módulo desativado, e uma chamada indisponível vira erro de compilação, e não uma recusa em runtime |
a interface de um módulo | segue o ator, não o lado (veja Quem toma as decisões): um build room-visitor vê entrar, sair e ler; um build room-owner vê também expulsar, fechar e configurar; e whoami informa quais interfaces o ator atual libera |
Quem distribui os papéis. Conceder e revogar o papel de um jogador, assim como o papel padrão que o projeto declara para um jogador novo, são operações de Auth & Players — esse módulo é dono das identidades, e o papel é resolvido pela identidade que está na credencial.
Erros
- O que um predicado esconde responde
not found, nãoforbidden: senão a própria recusa contaria a quem chamou que aquilo existe. - Um direito que quem chama não tem responde
forbiddenquando a existência do alvo não é segredo, e a resposta diz o que faltou em vez de falhar sem explicação. - Um campo fora da máscara não aparece na resposta, em vez de vir presente e vazio: um valor vazio e um valor mascarado seriam indistinguíveis.
- Um papel que inclui a si mesmo, diretamente ou por uma cadeia, é um erro de configuração — recusado já como declaração, e não resolvido em runtime.
- A delegação nunca amplia a capacidade: uma chamada que o ator não poderia fazer por conta própria é recusada quando feita em nome de um jogador.
Limites
Os números chegam com o capítulo de limites da plataforma; o que acontece em cada teto já está definido.
- O tamanho de uma seleção sob um predicado de linhas é limitado, e o modelo de ACL declara esse limite em vez de descobri-lo na prática. Uma leitura acima do teto recebe o teto em linhas, mais o marcador de que foi cortada — nunca uma página menor sem aviso.
- O limite de desatualização de uma permissão resolvida é declarado, e uma revogação não espera por ele: invalida na hora.