Khi xây dựng bất kỳ ứng dụng nào hướng đến công chúng, điều cực kỳ quan trọng là bạn phải bảo vệ dữ liệu được lưu trữ trong hệ thống. Đối với LLM, bạn cần phải cẩn thận hơn để đảm bảo rằng mô hình chỉ truy cập vào dữ liệu cần thiết, các lệnh gọi công cụ được đưa vào phạm vi thích hợp cho người dùng gọi LLM và luồng chỉ được các ứng dụng khách đã xác minh gọi.
Firebase Genkit cung cấp các cơ chế để quản lý chính sách uỷ quyền và ngữ cảnh. Các luồng chạy trên Firebase có thể sử dụng lệnh gọi lại chính sách xác thực (hoặc trình trợ giúp). Ngoài ra, Firebase cũng cung cấp ngữ cảnh xác thực vào luồng mà tại đó, Firebase có thể tự kiểm tra. Đối với các luồng không phải Hàm, bạn có thể quản lý và thiết lập quyền xác thực thông qua phần mềm trung gian.
Uỷ quyền trong Flow
Flow có thể kiểm tra quyền uỷ quyền theo hai cách: liên kết yêu cầu (ví dụ: onCallGenkit
cho Cloud Functions for Firebase hoặc express
) có thể thực thi quyền uỷ quyền hoặc các khung đó có thể truyền chính sách xác thực đến flow, trong đó flow có quyền truy cập vào thông tin xác thực được quản lý trong flow.
import { genkit, z, UserFacingError } from 'genkit';
const ai = genkit({ ... });
export const selfSummaryFlow = ai.defineFlow( {
name: 'selfSummaryFlow',
inputSchema: z.object({ uid: z.string() }),
outputSchema: z.string(),
}, async (input, { context }) => {
if (!context.auth) {
throw new UserFacingErrorError('UNAUTHENTICATED', 'Unauthenticated');
}
if (input.uid !== context.auth.uid) {
throw new UserFacingError('PERMISSION_DENIED', 'You may only summarize your own profile data.');
}
// Flow logic here...
});
Trong trường hợp này, việc liên kết yêu cầu sẽ điền sẵn context.auth
. Ví dụ: onCallGenkit
tự động điền context.auth
(Xác thực Firebase), context.app
(Kiểm tra ứng dụng Firebase) và context.instanceIdToken
(Gửi thông báo qua đám mây của Firebase). Khi gọi một luồng theo cách thủ công, bạn có thể thêm ngữ cảnh xác thực của riêng mình theo cách thủ công.
// Error: Authorization required.
await selfSummaryFlow({ uid: 'abc-def' });
// Error: You may only summarize your own profile data.
await selfSummaryFlow.run(
{ uid: 'abc-def' },
{
context: { auth: { uid: 'hij-klm' } },
}
);
// Success
await selfSummaryFlow(
{ uid: 'abc-def' },
{
context: { auth: { uid: 'abc-def' } },
}
);
Khi chạy bằng giao diện người dùng phát triển Genkit, bạn có thể truyền đối tượng Auth bằng cách nhập JSON vào thẻ "Auth JSON": {"uid": "abc-def"}
.
Bạn cũng có thể truy xuất ngữ cảnh xác thực cho luồng bất cứ lúc nào trong luồng bằng cách gọi ai.currentContext()
, bao gồm cả trong các hàm do luồng gọi:
import { genkit, z } from 'genkit';
const ai = genkit({ ... });;
async function readDatabase(uid: string) {
const auth = ai.currentContext()?.auth;
// Note: the shape of context.auth depends on the provider. onCallGenkit puts
// claims information in auth.token
if (auth?.token?.admin) {
// Do something special if the user is an admin
} else {
// Otherwise, use the `uid` variable to retrieve the relevant document
}
}
export const selfSummaryFlow = ai.defineFlow(
{
name: 'selfSummaryFlow',
inputSchema: z.object({ uid: z.string() }),
outputSchema: z.string(),
authPolicy: ...
},
async (input) => {
await readDatabase(input.uid);
}
);
Khi kiểm thử luồng bằng các công cụ phát triển Genkit, bạn có thể chỉ định đối tượng xác thực này trong giao diện người dùng hoặc trên dòng lệnh bằng cờ --context
:
genkit flow:run selfSummaryFlow '{"uid": "abc-def"}' --context '{"auth": {"email_verified": true}}'
Uỷ quyền bằng Cloud Functions cho Firebase
Các SDK Cloud Functions cho Firebase hỗ trợ Genkit, bao gồm cả việc tích hợp với Firebase Auth / Google Cloud Identity Platform, cũng như hỗ trợ tích hợp sẵn tính năng Firebase App Check.
Xác thực người dùng
Trình bao bọc onCallGenkit()
do thư viện Hàm Firebase cung cấp có hỗ trợ tích hợp cho SDK ứng dụng của Cloud Functions cho Firebase.
Khi bạn sử dụng các SDK này, tiêu đề Firebase Auth sẽ tự động được đưa vào miễn là ứng dụng của bạn cũng đang sử dụng SDK Firebase Auth.
Bạn có thể sử dụng Firebase Auth để bảo vệ các luồng được xác định bằng onCallGenkit()
:
import { genkit } from 'genkit';
import { onCallGenkit } from 'firebase-functions/https';
const ai = genkit({ ... });;
const selfSummaryFlow = ai.defineFlow({
name: 'selfSummaryFlow',
inputSchema: z.string(),
outputSchema: z.string(),
}, async (input) => {
// Flow logic here...
});
export const selfSummary = onCallGenkit({
authPolicy: (auth) => auth?.token?.['email_verified'] && auth?.token?.['admin'],
}, selfSummaryFlow);
Khi bạn sử dụng onCallGenkit
, context.auth
sẽ được trả về dưới dạng một đối tượng có uid
cho mã nhận dạng người dùng và token
là DecodedIdToken.
Bạn có thể truy xuất đối tượng này bất cứ lúc nào bằng cách sử dụng ai.currentContext()
như đã lưu ý trước đó. Khi chạy luồng này trong quá trình phát triển, bạn sẽ truyền đối tượng người dùng theo cách tương tự:
genkit flow:run selfSummaryFlow '{"uid": "abc-def"}' --context '{"auth": {"admin": true}}'
Bất cứ khi nào bạn hiển thị một Hàm trên đám mây cho Internet rộng lớn hơn, bạn phải sử dụng một số cơ chế uỷ quyền để bảo vệ dữ liệu của mình và dữ liệu của khách hàng. Tuy nhiên, có những lúc bạn cần triển khai một Hàm trên đám mây không có quy trình kiểm tra quyền dựa trên mã (ví dụ: Hàm của bạn không thể gọi được trên toàn cầu nhưng được bảo vệ bằng Cloud IAM).
Cloud Functions cho Firebase cho phép bạn thực hiện việc này bằng cách sử dụng thuộc tính invoker
,
thuộc tính này kiểm soát quyền truy cập IAM. Giá trị đặc biệt 'private'
sẽ để hàm ở chế độ cài đặt IAM mặc định, nghĩa là chỉ những phương thức gọi có vai trò Trình gọi Cloud Run mới có thể thực thi hàm. Thay vào đó, bạn có thể cung cấp địa chỉ email của một người dùng hoặc tài khoản dịch vụ sẽ được cấp quyền gọi chính xác hàm này.
import { onCallGenkit } from 'firebase-functions/https'
const selfSummaryFlow = ai.defineFlow({
name: 'selfSummaryFlow',
inputSchema: z.string(),
outputSchema: z.string(),
}, async (input) => {
// Flow logic here...
});
export const selfSummary = onCallGenkit({
invoker: 'private',
}, selfSummaryFlow);
Tính toàn vẹn của ứng dụng
Việc xác thực tự thân sẽ giúp bảo vệ ứng dụng của bạn rất nhiều. Tuy nhiên, bạn cũng cần đảm bảo rằng chỉ các ứng dụng khách của bạn mới gọi các hàm của bạn. Trình bổ trợ Firebase cho genkit có khả năng hỗ trợ hàng đầu cho Kiểm tra ứng dụng Firebase. Hãy thực hiện việc này bằng cách thêm các tuỳ chọn cấu hình sau vào onCallGenkit()
:
import { onCallGenkit } from 'firebase-functions/https';
const selfSummaryFlow = ai.defineFlow({
name: 'selfSummaryFlow',
inputSchema: z.string(),
outputSchema: z.string(),
}, async (input) => {
// Flow logic here...
});
export const selfSummary = onCallGenkit({
// These two fields for app check. The consumeAppCheckToken option is for
// replay protection, and requires additional client configuration. See the
// App Check docs.
enforceAppCheck: true,
consumeAppCheckToken: true,
authPolicy: ...,
}, selfSummaryFlow);
Cấp quyền HTTP không phải Firebase
Khi triển khai luồng đến ngữ cảnh máy chủ bên ngoài Cloud Functions cho Firebase, bạn nên có cách thiết lập quy trình kiểm tra uỷ quyền của riêng mình cùng với các luồng tích hợp.
Sử dụng ContextProvider
để điền các giá trị ngữ cảnh như auth
và để cung cấp chính sách khai báo hoặc lệnh gọi lại chính sách. SDK Genkit cung cấp các ContextProvider
như apiKey
và các trình bổ trợ cũng có thể hiển thị các ContextProvider
đó. Ví dụ: trình bổ trợ @genkit-ai/firebase/context
hiển thị một trình cung cấp ngữ cảnh để xác minh thông tin xác thực Firebase Auth và điền thông tin đó vào ngữ cảnh.
Với mã như sau, có thể xuất hiện trong nhiều ứng dụng:
// Express app with a simple API key
import { genkit, z } from 'genkit';
const ai = genkit({ ... });;
export const selfSummaryFlow = ai.defineFlow(
{
name: 'selfSummaryFlow',
inputSchema: z.object({ uid: z.string() }),
outputSchema: z.string(),
},
async (input) => {
// Flow logic here...
}
);
Bạn có thể bảo mật một ứng dụng Express "flow server" (máy chủ luồng) đơn giản bằng cách viết:
import { apiKey } from "genkit";
import { startFlowServer, withContext } from "@genkit-ai/express";
startFlowServer({
flows: [
withContext(selfSummaryFlow, apiKey(process.env.REQUIRED_API_KEY))
],
});
Hoặc bạn có thể tạo một ứng dụng Express tuỳ chỉnh bằng các công cụ tương tự:
import { apiKey } from "genkit";
import * as express from "express";
import { expressHandler } from "@genkit-ai/express;
const app = express();
// Capture but don't validate the API key (or its absence)
app.post('/summary', expressHandler(selfSummaryFlow, { contextProvider: apiKey()}))
app.listen(process.env.PORT, () => {
console.log(`Listening on port ${process.env.PORT}`);
})
ContextProvider
tóm tắt khung web, vì vậy, các công cụ này cũng hoạt động trong các khung khác như Next.js. Sau đây là ví dụ về một ứng dụng Firebase được xây dựng trên Next.js.
import { appRoute } from "@genkit-ai/express";
import { firebaseContext } from "@genkit-ai/firebase";
export const POST = appRoute(selfSummaryFlow, { contextProvider: firebaseContext })
Để biết thêm thông tin về cách sử dụng Express, hãy xem hướng dẫn về Cloud Run.