跳转至

设置自定义身份验证

在本教程中,我们将构建一个只允许特定用户访问的聊天机器人。我们将从 LangGraph 模板开始,逐步添加基于令牌的安全性。在结束时,你将拥有一个在允许访问之前检查有效令牌的工作聊天机器人。

这是我们身份验证系列的第 1 部分:

  1. 设置自定义身份验证(你在这里) - 控制谁可以访问你的机器人
  2. 使对话私密化 - 让用户进行私密对话
  3. 连接身份验证提供程序 - 添加真实用户帐户并使用 OAuth2 进行生产验证

本指南假设你对以下概念有基本了解:

Note

自定义身份验证仅适用于 LangGraph Platform SaaS 部署或企业自托管部署。

1. 创建你的应用

使用 LangGraph 启动模板创建一个新的聊天机器人:

pip install -U "langgraph-cli[inmem]"
langgraph new --template=new-langgraph-project-python custom-auth
cd custom-auth
npx @langchain/langgraph-cli new --template=new-langgraph-project-typescript custom-auth
cd custom-auth

模板为我们提供了一个占位符 LangGraph 应用。通过安装本地依赖项并运行开发服务器来试用它:

pip install -e .
langgraph dev
npm install
npm run langgraph dev

服务器将启动并在你的浏览器中打开 studio:

> - 🚀 API: http://127.0.0.1:2024
> - 🎨 Studio UI: https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024
> - 📚 API Docs: http://127.0.0.1:2024/docs
>
> 此内存服务器专为开发和测试而设计。
> 对于生产使用,请使用 LangSmith 部署。

如果你要在公共互联网上自托管此应用,任何人都可以访问它!

No auth

2. 添加身份验证

现在你有了一个基础的 LangGraph 应用,向其添加身份验证。

Note

在本教程中,你将从硬编码的令牌开始作为示例。你将在第三个教程中获得"生产就绪"的身份验证方案。

Auth 对象允许你注册一个身份验证函数,LangGraph 平台将在每个请求上运行该函数。此函数接收每个请求并决定是接受还是拒绝。

创建一个新文件 src/security/auth.py。这是你的代码检查用户是否被允许访问你的机器人的地方:

src/security/auth.py
from langgraph_sdk import Auth

# This is our toy user database. Do not do this in production
VALID_TOKENS = {
    "user1-token": {"id": "user1", "name": "Alice"},
    "user2-token": {"id": "user2", "name": "Bob"},
}

# The "Auth" object is a container that LangGraph will use to mark our authentication function
auth = Auth()


# The `authenticate` decorator tells LangGraph to call this function as middleware
# for every request. This will determine whether the request is allowed or not
@auth.authenticate
async def get_current_user(authorization: str | None) -> Auth.types.MinimalUserDict:
    """Check if the user's token is valid."""
    assert authorization
    scheme, token = authorization.split()
    assert scheme.lower() == "bearer"
    # Check if token is valid
    if token not in VALID_TOKENS:
        raise Auth.exceptions.HTTPException(status_code=401, detail="Invalid token")

    # Return user info if valid
    user_data = VALID_TOKENS[token]
    return {
        "identity": user_data["id"],
    }

注意你的身份验证处理程序做了两件重要的事情:

  1. 检查请求的 Authorization 头中是否提供了有效令牌
  2. 返回用户的身份

Auth 对象允许你注册一个身份验证函数,LangGraph 平台将在每个请求上运行该函数。此函数接收每个请求并决定是接受还是拒绝。

创建一个新文件 src/security/auth.ts。这是你的代码检查用户是否被允许访问你的机器人的地方:

src/security/auth.ts
import { Auth } from "@langchain/langgraph-sdk";

// This is our toy user database. Do not do this in production
const VALID_TOKENS: Record<string, { id: string; name: string }> = {
  "user1-token": { id: "user1", name: "Alice" },
  "user2-token": { id: "user2", name: "Bob" },
};

// The "Auth" object is a container that LangGraph will use to mark our authentication function
const auth = new Auth();
  // The `authenticate` method tells LangGraph to call this function as middleware
  // for every request. This will determine whether the request is allowed or not
  .authenticate((request) => {
    // Our authentication handler from the previous tutorial.
    const apiKey = request.headers.get("x-api-key");
    if (!apiKey || !isValidKey(apiKey)) {
      throw new HTTPException(401, "Invalid API key");
    }

    const [scheme, token] = apiKey.split(" ");
    if (scheme.toLowerCase() !== "bearer") {
      throw new Error("Bearer token required");
    }

    if (!VALID_TOKENS[token]) {
      throw new HTTPException(401, "Invalid token");
    }

    const userData = VALID_TOKENS[token];
    return {
      identity: userData.id,
    };
  });

export { auth };

注意你的身份验证处理程序做了两件重要的事情:

  1. 检查请求的 Authorization 头中是否提供了有效令牌
  2. 返回用户的身份

现在通过向 langgraph.json 配置中添加以下内容来告诉 LangGraph 使用身份验证:

langgraph.json
{
  "dependencies": ["."],
  "graphs": {
    "agent": "./src/agent/graph.py:graph"
  },
  "env": ".env",
  "auth": {
    "path": "src/security/auth.py:auth"
  }
}
langgraph.json
{
  "dependencies": ["."],
  "graphs": {
    "agent": "./src/agent/graph.ts:graph"
  },
  "env": ".env",
  "auth": {
    "path": "src/security/auth.ts:auth"
  }
}

3. 测试你的机器人

再次启动服务器来测试一切:

langgraph dev --no-browser

如果你没有添加 --no-browser,studio UI 将在浏览器中打开。你可能想知道,studio 如何仍然能够连接到我们的服务器?默认情况下,即使使用自定义身份验证,我们也允许来自 LangGraph studio 的访问。这使得在 studio 中开发和测试你的机器人更容易。你可以通过在身份验证配置中设置 disable_studio_auth: "true" 来删除此替代身份验证选项:

{
  "auth": {
    "path": "src/security/auth.py:auth",
    "disable_studio_auth": "true"
  }
}
{
  "auth": {
    "path": "src/security/auth.ts:auth",
    "disable_studio_auth": "true"
  }
}

4. 与你的机器人聊天

现在只有当你在请求头中提供有效令牌时才能访问机器人。然而,用户仍然能够访问彼此的资源,直到你在教程的下一部分添加资源授权处理程序

Authentication, no authorization handlers

在文件或 notebook 中运行以下代码:

from langgraph_sdk import get_client

# Try without a token (should fail)
client = get_client(url="http://localhost:2024")
try:
    thread = await client.threads.create()
    print("❌ Should have failed without token!")
except Exception as e:
    print("✅ Correctly blocked access:", e)

# Try with a valid token
client = get_client(
    url="http://localhost:2024", headers={"Authorization": "Bearer user1-token"}
)

# Create a thread and chat
thread = await client.threads.create()
print(f"✅ Created thread as Alice: {thread['thread_id']}")

response = await client.runs.create(
    thread_id=thread["thread_id"],
    assistant_id="agent",
    input={"messages": [{"role": "user", "content": "Hello!"}]},
)
print("✅ Bot responded:")
print(response)

在 TypeScript 文件中运行以下代码:

import { Client } from "@langchain/langgraph-sdk";

async function testAuth() {
  // Try without a token (should fail)
  const clientWithoutToken = new Client({ apiUrl: "http://localhost:2024" });
  try {
    const thread = await clientWithoutToken.threads.create();
    console.log("❌ Should have failed without token!");
  } catch (e) {
    console.log("✅ Correctly blocked access:", e);
  }

  // Try with a valid token
  const client = new Client({
    apiUrl: "http://localhost:2024",
    headers: { Authorization: "Bearer user1-token" },
  });

  // Create a thread and chat
  const thread = await client.threads.create();
  console.log(`✅ Created thread as Alice: ${thread.thread_id}`);

  const response = await client.runs.create(thread.thread_id, "agent", {
    input: { messages: [{ role: "user", content: "Hello!" }] },
  });
  console.log("✅ Bot responded:");
  console.log(response);
}

testAuth().catch(console.error);

你应该看到:

  1. 没有有效令牌,我们无法访问机器人
  2. 有了有效令牌,我们可以创建线程并聊天

恭喜!你已经构建了一个只允许"已认证"用户访问的聊天机器人。虽然此系统(目前)还未实现生产就绪的安全方案,但我们已经学习了如何控制对机器人访问的基本机制。在下一个教程中,我们将学习如何为每个用户提供他们自己的私密对话。

Next steps

现在你可以控制谁访问你的机器人,你可能想要:

  1. 继续教程,转到使对话私密以了解资源授权。
  2. 阅读更多关于身份验证概念的内容。
  1. 查看 API 参考以了解更多身份验证详细信息。
  1. 查看 API 参考以了解更多身份验证详细信息。