كيفية: التحقق من صحة مستخدم أنشأ حاوية

عند إنشاء حاوية في Azure Fluid Relay، يمكن استخدام JWT الذي يوفره ITokenProvider لطلب الإنشاء مرة واحدة فقط. بعد إنشاء حاوية، يجب على العميل إنشاء JWT جديد يحتوي على معرف المستند (وهو بالفعل معرف الحاوية) الذي توفره الخدمة في وقت الإنشاء. إذا كان التطبيق يحتوي على خدمة تخويل تدير التحكم في الوصول إلى الحاوية، فإنه يحتاج إلى معرفة من أنشأ حاوية بمعرف معين من أجل تخويل إنشاء JWT جديد للوصول إلى تلك الحاوية.

إبلاغ خدمة التخويل عند إنشاء حاوية

يمكن للتطبيق ربط دورة حياة إنشاء الحاوية عن طريق تنفيذ مستند عام طريقةPostCreateCallback() في الخاص به TokenProvider. (يمكن أن يكون اسم هذه الدالة مربكا. إنها حقا رد اتصال لإنشاء حاوية ما بعد.) سيتم تشغيل رد الاتصال هذا مباشرة بعد إنشاء الحاوية، قبل أن يطلب العميل JWT الجديد الذي يحتاجه للحصول على أذونات القراءة/الكتابة إلى الحاوية التي تم إنشاؤها.

documentPostCreateCallback() يتلقى معلمتين: 1) معرف الحاوية التي تم إنشاؤها (تسمى أيضا "معرف المستند") و2) JWT موقعة من قبل الخدمة بدون نطاقات أذونات. يمكن لخدمة التخويل التحقق من JWT المحدد واستخدام المعلومات في JWT لمنح أذونات المستخدم الصحيحة للحاوية التي تم إنشاؤها حديثا.

إنشاء نقطة نهاية لرد اتصال إنشاء الحاوية

هذا المثال أدناه هو Azure Function استنادا إلى المثال في كيفية: كتابة TokenProvider باستخدام Azure Function.

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

(راجع أيضًا )