Sdílet prostřednictvím


Postupy: Ověření uživatele, který vytvořil kontejner

Při vytváření kontejneru ve službě Azure Fluid Relay lze JWT poskytnuté ITokenProviderem pro požadavek na vytvoření použít pouze jednou. Po vytvoření kontejneru musí klient vygenerovat nový JWT, který obsahuje ID dokumentu (což je ve skutečnosti ID kontejneru) poskytované službou při vytváření. Pokud má aplikace autorizační službu, která spravuje řízení přístupu ke kontejneru, potřebuje vědět, kdo vytvořil kontejner s daným ID, aby bylo možné autorizovat generování nového JWT pro přístup k danému kontejneru.

Informování autorizační služby při vytvoření kontejneru

Aplikace se může spojit s životním cyklem vytváření kontejneru implementací metody Public documentPostCreateCallback() v jeho TokenProvider. (Název této funkce může být matoucí. Je to opravdu zpětné volání pro následné vytvoření kontejneru .) Toto zpětné volání se aktivuje přímo po vytvoření kontejneru, než klient požádá o nový JWT, musí získat oprávnění ke čtení a zápisu do vytvořeného kontejneru.

Obdrží documentPostCreateCallback() dva parametry: 1) ID vytvořeného kontejneru (označovaného také jako ID dokumentu) a 2) JWT podepsané službou bez oborů oprávnění. Autorizační služba může ověřit dané prostředí JWT a pomocí informací v JWT udělit správná uživatelská oprávnění pro nově vytvořený kontejner.

Vytvoření koncového bodu pro zpětné volání pro vytvoření kontejneru

Níže uvedený příklad je funkce Azure Functions založená na příkladu v části Postupy: Zápis tokenprovideru pomocí funkce 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;

Implementace documentPostCreateCallback

Tato ukázková implementace níže rozšiřuje AzureFunctionTokenProvider a používá knihovnu axios k vytvoření požadavku HTTP na funkci Azure Functions použitou ke generování tokenů.

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,
            },
        });
    }
}

Viz také