如何创建并验证类GitHub格式的API访问令牌?
如何实现类似GitHub格式的API访问令牌?
GitHub这类ghp_前缀+固定长度的访问令牌,本质是密码学安全的不透明令牌,行业内主流实现方式是「随机令牌生成+数据库哈希映射」,完全可以解决你提到的方案问题,具体实现步骤如下:
核心思路
这类令牌的核心是:令牌本身是无意义的高熵随机字符串,前缀仅用于标识令牌类型(比如ghp_代表GitHub个人访问令牌),服务端通过数据库存储「令牌哈希值」与「用户信息、权限、过期时间」的映射关系来完成验证。
具体实现步骤
1. 自定义前缀
先确定固定前缀(比如app_),作用是:
- 快速区分令牌类型(比如后续可扩展
app_srv_代表服务端令牌) - 方便客户端和服务端快速识别合法令牌格式
2. 生成固定长度的随机主体
使用密码学安全的随机数生成器生成指定长度的随机字符串,确保不可预测性:
- 比如要生成36个字符的主体部分,可以用Base64URL编码(避免特殊字符,适合HTTP传输):
- Python示例:
secrets.token_urlsafe(27)(27字节的随机数据经Base64URL编码后正好是36个字符) - Node.js示例:
crypto.randomBytes(27).toString('base64url')
- Python示例:
- 不要用普通的随机函数(比如Python的
random模块),必须用密码学安全的实现,防止令牌被猜测
3. 数据库存储设计
不要存储明文令牌,只存储令牌的哈希值(用慢哈希算法,比如bcrypt、Argon2,防止数据库泄露后令牌被破解)。典型的表结构可以是:
| 字段名 | 类型 | 说明 |
|---|---|---|
| id | 自增整数 | 主键 |
| user_id | 外键 | 关联用户表ID |
| token_hash | 字符串 | 令牌的哈希值 |
| prefix | 字符串 | 令牌前缀(可选,方便筛选) |
| expires_at | datetime | 令牌过期时间(可选) |
| scopes | 字符串/JSON | 令牌权限范围(可选) |
4. 令牌验证流程
当客户端携带令牌请求API时:
- 服务端先拆分令牌的前缀和主体(可选验证前缀是否合法)
- 对整个令牌(前缀+主体)计算哈希值
- 去数据库中查询是否存在匹配的
token_hash,同时检查令牌是否过期、权限是否符合请求要求 - 如果匹配成功,就关联到对应的
user_id,完成身份验证
对你提出的三个方案的解答
- 加密用户ID方案:确实无法固定长度,而且这类方案属于「自包含令牌」,不需要数据库查询,但GitHub这类场景用不透明令牌更安全(令牌本身不携带用户信息,泄露后无法直接获取数据),因此没必要采用。
- 随机字符串方案:你的误解在于「验证逻辑」——不需要用用户ID去查令牌,而是用客户端发送的令牌哈希去数据库匹配对应的用户ID,这个方案是行业通用的核心实现方式,完全可行。
- JWT方案:JWT是自包含令牌,长度依赖编码内容,无法固定格式,且令牌本身携带用户信息,适合分布式无状态场景,但GitHub这类场景更倾向于不透明令牌,因为可以随时在数据库中吊销令牌,安全性更高。
最佳实践
- 给令牌设置过期时间,即使令牌泄露,危害也能控制在有效期内
- 提供用户手动吊销令牌的功能,增强账户安全性
- 记录令牌的使用日志(比如请求IP、时间),方便排查异常操作
内容的提问来源于stack exchange,提问作者Hrishikesh Kokate
相关产品推荐
相关产品推荐

