2. 智能体基础
身份认证和访问控制,说白了就是解决两个问题:「你是谁?」和「你能干什么?」。在智能体系统里,这两个问题比传统应用更棘手——因为智能体可能自己调用自己,也可能代表用户去调用别的服务。
我最早做智能体项目时,就踩过一个坑。当时一个对话智能体需要调用内部CRM系统查客户信息,我图省事直接配了个全局API Key。结果上线第三天,某个测试智能体误触发了删除客户数据的接口……嗯,从那以后,我再也不敢轻视访问控制。
OAuth2.0与JWT在智能体中的应用
先聊聊OAuth2.0。它本质上是一个授权委托协议。智能体作为客户端,代表用户去访问资源服务器。常见的流程是授权码模式(Authorization Code Flow),适合有后端的智能体应用。
JWT(JSON Web Token)则是OAuth2.0中常用的令牌格式。它把用户身份和权限信息直接编码在令牌里,省去了每次去认证服务器查数据库的麻烦。
核心流程:
- 用户授权智能体访问资源
- 智能体向认证服务器换取授权码
- 智能体用授权码换取JWT访问令牌
- 智能体携带JWT访问资源服务器
- 资源服务器验证JWT签名,提取用户信息
JWT的结构分为三部分:Header、Payload、Signature。Header声明签名算法,Payload放用户ID、角色、过期时间等声明,Signature用密钥对前两部分签名防篡改。
// JWT示例(解码后)
{
"header": {
"alg": "RS256",
"typ": "JWT"
},
"payload": {
"sub": "agent-001",
"user_id": "u-10086",
"role": "readonly",
"exp": 1718000000,
"iat": 1717996400
},
"signature": "Base64UrlEncode(header).Base64UrlEncode(payload) + 私钥签名"
}
我的经验:智能体场景下,JWT的过期时间要设短一些,建议15-30分钟。因为智能体可能长时间运行,令牌泄露风险比普通用户高。配合Refresh Token做无感续期,既安全又流畅。
为什么会推荐RS256而不是HS256?因为RS256用非对称密钥,资源服务器只需要公钥就能验证,私钥只保存在认证服务器。智能体数量一多,密钥分发管理就简单多了。
RBAC权限模型设计
RBAC(基于角色的访问控制)是我个人最常用的权限模型。它把权限分配给角色,再把角色分配给用户或智能体。这样权限管理就变成了角色管理,清晰很多。
在智能体系统里,我习惯把RBAC分成三层:
| 层级 | 说明 | 示例 |
|---|---|---|
| 用户层 | 自然人用户,拥有基础角色 | 普通员工、管理员、审计员 |
| 智能体层 | 智能体自身身份,拥有操作角色 | 只读智能体、读写智能体、管理员智能体 |
| 服务层 | 微服务或API资源,定义操作权限 | 查询客户、创建订单、删除数据 |
设计时要注意一个关键点:智能体的权限不能超过其所属用户的权限。比如用户只有只读权限,他创建的智能体就不能有写权限。这叫「权限向下兼容」原则。
我曾经踩过的坑:给智能体分配了「管理员」角色,结果智能体在循环调用中意外修改了系统配置。后来我加了一条硬规则——智能体角色必须显式声明,且不能继承用户的高权限角色。每个智能体只能拥有最小必要权限。
RBAC的数据库设计也不复杂,几张核心表就够了:
-- 核心表结构(简化版)
CREATE TABLE users (
id UUID PRIMARY KEY,
name VARCHAR(100),
role_id UUID REFERENCES roles(id)
);
CREATE TABLE roles (
id UUID PRIMARY KEY,
name VARCHAR(50), -- 'readonly', 'editor', 'admin'
description TEXT
);
CREATE TABLE permissions (
id UUID PRIMARY KEY,
resource VARCHAR(100), -- 'customer', 'order', 'config'
action VARCHAR(50) -- 'read', 'write', 'delete'
);
CREATE TABLE role_permissions (
role_id UUID REFERENCES roles(id),
permission_id UUID REFERENCES permissions(id),
PRIMARY KEY (role_id, permission_id)
);
你想想看,如果智能体要调用某个API,流程就是:验证JWT → 提取角色 → 查角色权限 → 比对资源操作 → 允许或拒绝。每一步都很清晰。
API密钥管理最佳实践
API密钥是智能体系统里最常见的认证方式之一。但很多人用得很随意,我见过直接把密钥硬编码在代码里的……那基本等于把家门钥匙贴在门上。
我个人总结了一套API密钥管理的最佳实践,分享给你:
- 密钥生成:使用足够长的随机字符串,至少32字节。推荐用
openssl rand -hex 32生成。 - 密钥存储:永远不要硬编码。用环境变量、密钥管理服务(如AWS Secrets Manager、HashiCorp Vault)或K8s Secret。
- 密钥轮换:设置有效期,定期轮换。我习惯90天强制轮换一次,配合灰度发布,新旧密钥共存24小时。
- 密钥吊销:一旦怀疑泄露,立即吊销。系统要支持实时黑名单,而不是等缓存过期。
- 最小权限:每个智能体只分配它需要的API密钥,不要用「万能密钥」。
一个小技巧:API密钥可以设计成两段式——前缀标识密钥归属(如 sk_agent_001_),后缀是真正的随机密钥。这样日志里看到密钥前缀就能快速定位是哪个智能体,排查问题很方便。
密钥验证时的性能也要注意。每次请求都查数据库太慢,我建议用哈希缓存:密钥首次验证通过后,把哈希值缓存在Redis里,设置TTL为5分钟。后续请求直接查缓存,性能提升明显。
// 密钥验证伪代码
function validateApiKey(apiKey) {
// 1. 提取前缀,定位智能体
const prefix = apiKey.split('_').slice(0, 3).join('_');
const agent = getAgentByPrefix(prefix);
if (!agent) return false;
// 2. 查缓存
const cached = redis.get(`apikey:${hash(apiKey)}`);
if (cached) return true;
// 3. 查数据库验证
const isValid = db.query(
'SELECT 1 FROM api_keys WHERE key_hash = ? AND agent_id = ? AND revoked = false',
[hash(apiKey), agent.id]
);
if (isValid) {
redis.setex(`apikey:${hash(apiKey)}`, 300, '1');
}
return isValid;
}
最后,我把这三块内容的关系画成了一张图,方便你理解整体架构:
总结一下:OAuth2.0 + JWT解决「你是谁」的问题,RBAC解决「你能干什么」的问题,API密钥管理解决「怎么安全地让你进来」的问题。三者配合,才能构建一个健壮的智能体安全体系。
嗯,这部分内容就到这里。记住一个原则:永远假设智能体会犯错,权限给到最小,日志留到最全。这样即使出问题,也能快速定位和止血。