방법: 컨테이너를 만든 사용자 유효성 검사

Azure Fluid Relay에서 컨테이너를 만들 때 만들기 요청에 대해 ITokenProvider에서 제공하는 JWT는 한 번만 사용할 수 있습니다. 컨테이너를 만든 후 클라이언트는 생성 시 서비스에서 제공하는 문서 ID(실제로 컨테이너 ID)를 포함하는 새 JWT를 생성해야 합니다. 애플리케이션에 컨테이너 액세스 제어를 관리하는 권한 부여 서비스가 있는 경우 해당 컨테이너에 액세스하기 위해 새 JWT 생성에 권한을 부여하기 위해 지정된 ID로 컨테이너를 만든 사용자를 알아야 합니다.

컨테이너를 만들 때 권한 부여 서비스에 알리기

애플리케이션은 해당 문서에서 공용 documentPostCreateCallback() 메서드를 구현하여 컨테이너 만들기 수명 주기에 연결할 수 있습니다 TokenProvider. (이 함수의 이름은 혼동될 수 있습니다. 컨테이너를 만든 후 의 콜백입니다.) 이 콜백은 컨테이너를 만든 후 클라이언트가 만든 컨테이너에 대한 읽기/쓰기 권한을 얻는 데 필요한 새 JWT를 요청하기 전에 직접 트리거됩니다.

documentPostCreateCallback() 1) 생성된 컨테이너의 ID("문서 ID"라고도 함) 및 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 라이브러리를 사용하여 토큰 생성에 사용되는 Azure Function에 대한 HTTP 요청을 만듭니다.

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

참고 항목