方法: コンテナーを作成したユーザーを検証する
Azure Fluid Relay でコンテナーを作成すると、作成要求に対して ITokenProvider によって指定された JWT は、1 回のみ使用できます。 コンテナーを作成した後、クライアントでは、作成時にサービスによって指定されたドキュメント ID (実際はコンテナー ID) を含む新しい JWT が生成される必要があります。 アプリケーションにコンテナー アクセス制御を管理する承認サービスがある場合、そのコンテナーにアクセスするための新しい JWT の生成を承認するには、特定の ID を持つコンテナーを作成したユーザーを把握する必要があります。
コンテナーが作成されたときに承認サービスに通知する
アプリケーションは、パブリック documentPostCreateCallback() メソッドをその中に実装することで、コンテナー作成ライフサイクルに TokenProvider
結び付けることができます。 (この関数の名前は混乱する可能性があります。これは実際には、コンテナーの作成後のコールバックです)。このコールバックは、作成されたコンテナーに対する読み取り/書き込みアクセス許可を取得する必要がある新しい JWT をクライアントが要求する前に、コンテナーを作成した直後にトリガーされます。
documentPostCreateCallback()
は、次の 2 つのパラメーターを受け取ります: 1) 作成されたコンテナーの 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 関数への 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,
},
});
}
}