Guide pratique pour valider un utilisateur qui a créé un conteneur

Lorsque vous créez un conteneur dans Azure Fluid Relay, le JWT fourni par ITokenProvider pour la demande de création ne peut être utilisé qu’une seule fois. Après avoir créé un conteneur, le client doit générer un nouveau JWT qui contient l’ID de document (qui est vraiment l’ID de conteneur) fourni par le service au moment de la création. Si une application a un service d’autorisation qui gère le contrôle d’accès au conteneur, il doit savoir qui a créé un conteneur avec un ID donné afin d’autoriser la génération d’un nouveau JWT pour l’accès à ce conteneur.

Informer un service d’autorisation lorsqu’un conteneur est créé

Une application peut se lier au cycle de vie de création de conteneur en implémentant une méthode documentPostCreateCallback() publique dans son TokenProvider. (Le nom de cette fonction peut être déroutant. Il s’agit vraiment d’un rappel pour la création de conteneurs post-conteneur.) Ce rappel est déclenché directement après la création du conteneur, avant qu’un client demande au nouveau JWT qu’il doit obtenir des autorisations de lecture/écriture sur le conteneur qui a été créé.

Le documentPostCreateCallback() paramètre reçoit deux paramètres : 1) l’ID du conteneur créé (également appelé « ID de document ») et 2) un JWT signé par le service sans étendue d’autorisation. Le service d’autorisation peut vérifier le JWT donné et utiliser les informations contenues dans le JWT pour accorder les autorisations utilisateur appropriées pour le conteneur nouvellement créé.

Créer un point de terminaison pour votre rappel de création de conteneur

Cet exemple ci-dessous est une fonction Azure basée sur l’exemple dans Comment faire : Rédiger un TokenProvider avec une Fonction Azure.

import { AzureFunction, Context, HttpRequest } from "@azure/functions";
import { ITokenClaims, IUser } from "@fluidframework/protocol-definitions";
import * as jwt from "jsonwebtoken";

// NOTE: retrieve the key from a secure location.
const key = "myTenantKey";

const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> {
    const token = (req.query.token || (req.body && req.body.token)) as string;
    const documentId = (req.query.documentId || (req.body && req.body.documentId)) as string;

    if (!token) {
        context.res = {
            status: 400,
            body: "No token provided in request",
        };
        return;
    }
    if (!documentId) {
        context.res = {
            status: 400,
            body: "No documentId provided in request",
        };
        return;
    }
    
    const claims = jwt.decode(token) as ITokenClaims;
    if (!claims) {
        context.res = {
            status: 403,
            body: "Missing token claims",
        };
        return;
    }

    const tenantId = claims.tenantId;
    if (!claims) {
        context.res = {
            status: 400,
            body: "No tenantId provided in token claims",
        };
        return;
    }
    if (!key) {
        context.res = {
            status: 404,
            body: `No key found for the provided tenantId: ${tenantId}`,
        };
        return;
    }
    try {
        jwt.verify(token, key);
    } catch (e) {
        if (e instanceof jwt.TokenExpiredError) {
            context.res = {
                status: 401,
                body: `Token is expired`,
            };
            return
        }
        context.res = {
            status: 403,
            body: `Token signed with invalid key`,
        }
        return;
    }

    const user: IUser = claims.user;
    // Pseudo-function: implement according to your needs
    giveUserPermissionsForContainer(documentId, user);

    context.res = {
        status: 200,
        body: "OK",
    };
};

export default httpTrigger;

Implémenter le documentPostCreateCallback

Cet exemple d’implémentation ci-dessous étend AzureFunctionTokenProvider et utilise la bibliothèque axios pour effectuer une requête HTTP à la fonction Azure utilisée pour générer des jetons.

import { AzureFunctionTokenProvider, AzureMember } from "@fluidframework/azure-client";
import axios from "axios";

/**
 * Token Provider implementation for connecting to an Azure Function endpoint for
 * Azure Fluid Relay token resolution.
 */
export class AzureFunctionTokenProviderWithContainerCreateCallback extends AzureFunctionTokenProvider {
    /**
     * Creates a new instance using configuration parameters.
     * @param azFunctionUrl - URL to Azure Function endpoint
     * @param user - User object
     */
    constructor(
        private readonly authAzFunctionUrl: string,
        azFunctionUrl: string,
        user?: Pick<AzureMember, "userId" | "userName" | "additionalDetails">,
    ) {
        super(azFunctionUrl, user);
    }

    // In this context, a document is another name for container, so you can think of this function
    // as if it were named containerPostCreateCallback.
    public async documentPostCreateCallback?(documentId: string, creationToken: string): Promise<void> {
        await axios.post(this.authAzFunctionUrl, {
            params: {
                documentId,
                token: creationToken,
            },
        });
    }
}

Voir aussi