Saltar al contenido principal
Cómo funciona el SDK

Esta página aún no está traducida: se muestra la versión en inglés.

Access & Roles

Los roles se componen, nunca se fijan en el código. Los permisos atómicos se combinan en roles. Los roles controlan el acceso a los datos hasta la fila y la columna, y deciden qué interfaces de módulo llega a ver una compilación. Esto reemplaza la división entre claves de cliente y de servidor: una credencial nombra una identidad, y sus roles se resuelven en cada solicitud.

Cuándo usarlo

  • Necesitas una credencial más acotada que “cliente” o “servidor”: detrás de ella, en cada solicitud, se resuelven roles compuestos.
  • El acceso a los datos tiene que detenerse en filas y columnas: alcance por región, máscaras de datos personales (PII), contratistas de solo lectura.
  • Una compilación solo debe ver las interfaces que desbloquea su rol: para un visitante de la sala (room), expulsar y cerrar directamente no existen.
  • Tu interfaz tiene que desactivar los botones exactamente cuando corresponde: CanI evalúa la misma política que va a aplicar el servidor.
  • No lo necesitas cuando los presets incluidos (player, room-owner, seller, …) ya coinciden con tus actores. Todos los módulos los respetan por defecto; el catálogo completo está en Conceptos básicos.

Quién hace qué

ActorQué hace en esta página
operatordeclara roles y políticas, fija límites por fila y columna, otorga roles, emite claves
match-organizerpersonal del torneo: tiene una clave con roles compuestos, decide quién entra, no puede hacer reembolsos
todo actorrevisa CanI antes de actuar; solo ve las interfaces que tiene desbloqueadas

En resumen

Declara entry-validator con límites por fila y columna, otórgalo y revisa CanI antes de actuar
[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()
Próximamente — Go

Todavía no está decidido cómo declarar con atributos en Go (O-1). Los ejemplos llegarán cuando se elija la forma de escribirlo.

// 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();

Un permiso atómico es un par formado por un recurso y uno de cuatro verbos: read, write, execute, administer. El conjunto de verbos es fijo, y un caso que no encaja divide el recurso en lugar de alargar la lista. Por eso, controlar la entrada de otra persona es Rooms.Membership.Administer y no un verbo propio ValidateEntry: actuar sobre la participación (membership) de otro actor es administración, mientras que unirte tú mismo es Rooms.Membership.Write sobre el mismo recurso.

El modelo

La ACL de datos es rol × operación × predicado de filas × máscara de campos: un solo modelo, idéntico tanto si se escribió en código como a través de la API o en la cuadrícula de roles del panel.

De qué está hecho el acceso.

TérminoQué es
permiso atómicoun par recurso × verbo. Los cuatro verbos son read (obtener, seleccionar, suscribirse), write (crear, cambiar, borrar y actuar por uno mismo: unirse, salir), execute (invocar una función, aplicar una habilidad) y administer (actuar sobre otros: expulsar, cerrar, forzar un cambio de estado)
rolun conjunto de permisos atómicos con nombre. Puede incluir otro rol
preset de rolviene construido sobre permisos atómicos y sigue funcionando sin cambios para los consumidores ya desplegados. Es un punto de partida, no una restricción: un proyecto declara sus propios roles con los mismos permisos atómicos
predicado de filasqué filas: un predicado booleano sobre valores de la sesión
máscara de camposqué campos, declarada por rol y por operación

En qué se resuelve una credencial.

CredencialQué desbloquea
clave de jugadorla lleva una compilación del juego hecha con el motor; el jugador (player) que está detrás llega con el inicio de sesión (sign-in), y la compilación ve las filas cl de cada tabla de operaciones
clave de hostla tiene un servidor dedicado o un cliente maestro, y sus roles desbloquean las filas mc
código subidose ejecuta con el rol backend-service del proyecto: eso es lo que verifica Authoritative = true en una tabla de clasificación (leaderboard)
un hook registradono otorga nada extra: tu función conserva el rol con el que se desplegó

La leyenda de etiquetas (fn / cl / mc / adm) está en Conceptos básicos.

Lo que vale para toda verificación.

SiempreQué es
una credencialno lleva lista de roles: nombra una identidad, y los roles se resuelven del lado del servidor en cada solicitud. Una revocación invalida al instante la resolución guardada en caché, en lugar de esperar a que venza su límite de antigüedad declarado
la delegacióncambia el alcance, nunca la capacidad: actuar en nombre de un jugador cambia qué filas se ven y a quién se atribuye una escritura, pero no otorga ninguna operación que el actor no tuviera ya
el verboresponde qué tipo de efecto es, y el predicado responde qué filas. Si dos casos solo difieren en de quién es la fila, eso es un predicado; si difiere el efecto mismo, es otra operación y quizá otro verbo. Por eso “expulsar” es administer y no write con un predicado amplio
un dueñosiempre se ve a sí mismo, diga lo que diga un predicado
la visibilidadno es seguridad: una optimización de canales y un permiso son mecanismos distintos, y ninguno reemplaza al otro
un módulo deshabilitadono tiene interfaz: si un módulo está habilitado o no es una propiedad de la compilación, así que la generación de código no emite nada para uno deshabilitado, y una llamada no disponible es un error de compilación y no un rechazo en runtime
la interfaz de un módulodepende del actor y no del lado (consulta Quién toma las decisiones): una compilación room-visitor ve unirse, salir y leer; una compilación room-owner ve además expulsar, cerrar y configurar; y whoami informa qué interfaces desbloquea el actor actual

Quién entrega un rol. Otorgar y revocar un rol a un jugador, y el rol predeterminado que el proyecto declara para un jugador nuevo, son operaciones de Auth & Players: ese módulo es dueño de las identidades, y el rol se resuelve según la identidad que figura en la credencial.

Errores

  • Lo que un predicado oculta responde not found, no forbidden: de lo contrario, el propio rechazo le diría a quien llama que eso existe.
  • Un derecho que quien llama no tiene responde forbidden cuando la existencia del sujeto no es un secreto, y la respuesta nombra lo que faltaba en lugar de fallar sin más.
  • Un campo fuera de la máscara no aparece en la respuesta, en vez de aparecer vacío: si no, un valor vacío y uno enmascarado serían indistinguibles.
  • Un rol que se incluye a sí mismo, directamente o a través de una cadena, es un error de configuración: se rechaza como declaración en lugar de resolverse en runtime.
  • La delegación nunca amplía la capacidad: una llamada que el actor no podría hacer por su cuenta se rechaza también cuando la hace en nombre de un jugador.

Límites

Los números llegarán con el capítulo de límites de la plataforma; lo que pasa en cada tope ya está definido.

  • El tamaño de una selección bajo un predicado de filas está acotado, y el modelo de ACL declara ese límite en lugar de descubrirlo sobre la marcha. Una lectura que supera el tope recibe tantas filas como permite el tope, más la marca que indica que se cortó; nunca una página más corta sin aviso.
  • El límite de antigüedad de un permiso resuelto está declarado, y una revocación no espera a que venza: invalida al instante.