Практическое руководство. Проверка пользователя, создавшего контейнер

При создании контейнера в Ретрансляторе Жидкости Azure JWT, предоставляемого ITokenProvider для запроса на создание, можно использовать только один раз. После создания контейнера клиент должен создать новый JWT, содержащий идентификатор документа (который действительно является идентификатором контейнера), предоставленным службой во время создания. Если у приложения есть служба авторизации, которая управляет доступом к контейнеру, необходимо знать, кто создал контейнер с заданным идентификатором, чтобы авторизовать создание нового JWT для доступа к нему.

Сообщите службе авторизации при создании контейнера

Приложение может связать жизненный цикл создания контейнера, реализовав в ней TokenProviderоткрытый метод documentPostCreateCallback(). (Имя этой функции может быть запутано. Это действительно обратный вызов для создания контейнера post.) Этот обратный вызов будет активирован непосредственно после создания контейнера, прежде чем клиент запрашивает новый JWT, он должен получить разрешения на чтение и запись для созданного контейнера.

Получает documentPostCreateCallback() два параметра: 1) идентификатор созданного контейнера (также называемый идентификатором документа) и 2) JWT, подписанный службой без разрешений область. Служба авторизации может проверить заданный JWT и использовать сведения в JWT, чтобы предоставить правильные разрешения пользователя для только что созданного контейнера.

Создание конечной точки для обратного вызова создания контейнера

В этом примере ниже приведен пример функции Azure, основанный на примере в статье "Практическое руководство. Запись tokenProvider с помощью функции 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;

Реализация documentPostCreateCallback

В этом примере реализация ниже расширяет AzureFunctionTokenProvider и использует библиотеку axios для выполнения HTTP-запроса к функции Azure, используемой для создания маркеров.

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

См. также