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:
CanIevalú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é
| Actor | Qué hace en esta página |
|---|---|
operator | declara roles y políticas, fija límites por fila y columna, otorga roles, emite claves |
match-organizer | personal del torneo: tiene una clave con roles compuestos, decide quién entra, no puede hacer reembolsos |
todo actor | revisa CanI antes de actuar; solo ve las interfaces que tiene desbloqueadas |
En resumen
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()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érmino | Qué es |
|---|---|
permiso atómico | un 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) |
rol | un conjunto de permisos atómicos con nombre. Puede incluir otro rol |
preset de rol | viene 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 filas | qué filas: un predicado booleano sobre valores de la sesión |
máscara de campos | qué campos, declarada por rol y por operación |
En qué se resuelve una credencial.
| Credencial | Qué desbloquea |
|---|---|
clave de jugador | la 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 host | la tiene un servidor dedicado o un cliente maestro, y sus roles desbloquean las filas mc |
código subido | se ejecuta con el rol backend-service del proyecto: eso es lo que verifica Authoritative = true en una tabla de clasificación (leaderboard) |
un hook registrado | no 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.
| Siempre | Qué es |
|---|---|
una credencial | no 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ón | cambia 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 verbo | responde 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ño | siempre se ve a sí mismo, diga lo que diga un predicado |
la visibilidad | no es seguridad: una optimización de canales y un permiso son mecanismos distintos, y ninguno reemplaza al otro |
un módulo deshabilitado | no 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ódulo | depende 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, noforbidden: de lo contrario, el propio rechazo le diría a quien llama que eso existe. - Un derecho que quien llama no tiene responde
forbiddencuando 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.