Block a user
@abds10/capability-auth (1.0.3)
Published 2026-09-10 19:55:35 +00:00 by deploy
Installation
@abds10:registry=https://git.abds10.cn/api/packages/deploy/npm/npm install @abds10/capability-auth@1.0.3"@abds10/capability-auth": "1.0.3"About this package
ABDS10 统一鉴权:JWKS 本地验签、会话校验、角色/服务/设备令牌中间件
@abds10/capability-auth
跨项目统一鉴权。各项目不再自己实现登录/密码逻辑,只装这一个包。
规范:
docs/standards/跨项目互通标准.md第一、三章 账户中心:account.abds10.cn
它做什么
| 能力 | 说明 |
|---|---|
| 本地验签会话 | 用 JWKS 公钥验签会话 JWT,不回调账户中心(账户中心离线不影响已登录用户) |
| 授权版本校验 | 本地缓存 sub → ver(TTL 60 秒),实现"停用/改密最长 60 秒全网生效" |
| 授权与角色 | requireEntitlement / requireAppRole,角色语义由各项目自定义 |
| 服务令牌校验 | 调账户中心校验 svc_*,带 scope 与家庭绑定检查,结果短 TTL 缓存 |
| 设备令牌校验 | 调账户中心校验 dev_*,并把"能访问哪些路径"的权威留在中心 |
| Next 中间件 | withSso(manifest, config, responses) 一行接入 |
设计边界(重要)
- 零框架依赖:核心只用 Web 标准 API,可在 Node / Edge Runtime / Workers 运行
- 零数据库依赖:本包不连任何库。需要"实时"确认的一律走账户中心的 HTTP 接口, 各应用不需要复制令牌表
- 不读环境变量:配置显式传入,便于测试,也避免各项目变量命名不一致
安装
npm install @abds10/capability-auth @abds10/contracts
需要在自己的 .npmrc 里指向 Gitea 包仓库:
@abds10:registry=https://git.abds10.cn/api/packages/deploy/npm/
//git.abds10.cn/api/packages/deploy/npm/:_auth=<base64(deploy:令牌)>
接入(Next.js,四步)
1. 建一个单例 Auth
// src/lib/auth.ts
import { createAuth } from '@abds10/capability-auth'
export const auth = createAuth({
accountBaseUrl: process.env.ACCOUNT_BASE_URL!,
appId: 'aiwrite',
serviceToken: process.env.ACCOUNT_SERVICE_TOKEN!,
// 可选:
// versionCacheTtlMs: 60_000, // 「停用最长多久生效」的上界
// onCenterUnavailable: 'deny', // 中心不可达时:'deny' 拒绝 / 'stale' 放行
})
2. proxy.ts / middleware.ts 三行接入
Next 16 起 middleware 约定更名为 proxy:
// src/proxy.ts
import { NextResponse } from 'next/server'
import { withSso, type ResponseFactory, type SsoRequest } from '@abds10/capability-auth/next'
import manifest from '../app.manifest.json' with { type: 'json' }
/** 把 NextResponse 适配成包需要的接口(换框架时只改这一处) */
const responses: ResponseFactory = {
json: (body, init) => NextResponse.json(body, init),
text: (body, init) => new NextResponse(body, init),
redirect: (url) => NextResponse.redirect(url),
next: () => NextResponse.next(),
}
export default withSso(manifest, {
accountBaseUrl: process.env.ACCOUNT_BASE_URL!,
appId: manifest.app.id,
serviceToken: process.env.ACCOUNT_SERVICE_TOKEN!,
}, responses)
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp|ico)$).*)'],
}
buildMatcher(publicPaths)可以从 manifest 生成 matcher 字符串, 但 Next 要求 matcher 是静态字面量,所以最终仍要手写常量。
3. 在页面/接口里取当前用户
import { requireUser, requireAppRole, requireService } from '@abds10/capability-auth'
import { auth } from '@/lib/auth'
// Route Handler
export async function GET(req: Request) {
const r = await auth.sessions.fromRequest(req)
if (!r.ok) return Response.json({ error: r.message }, { status: 401 })
const user = r.value.principal // { kind: 'user', id: 'acc_...', entitlements, familyId }
// 业务权限自己判断,例如:
if (!(user.entitlements?.['aiwrite'] ?? []).includes('OWNER')) {
return Response.json({ error: '需要 OWNER' }, { status: 403 })
}
return Response.json({ accountId: user.id })
}
Server Component 里没有 Request 对象,用 cookies() 读出 Cookie 再调 auth.sessions.verifyToken(token)。
4. 被其他项目调用时校验服务令牌
import { requireService } from '@abds10/capability-auth'
import { auth } from '@/lib/auth'
export async function POST(req: Request) {
const svc = await requireService(auth, req, { scope: 'task:write' })
if (!svc.ok) return Response.json({ error: svc.message }, { status: 401 })
// svc.value.ownerApp === 'assistant'
}
关键行为与参数
| 参数 | 默认 | 含义 |
|---|---|---|
versionCacheTtlMs |
60000 | 授权版本的本地缓存时长。这就是"停用/改密后最长多久全网生效" |
jwksCacheTtlMs |
6 小时 | 公钥文档多久确认一次。已取到的密钥单独保留 24 小时,中心抖动时不误判 |
tokenCacheTtlMs |
30000 | 服务/设备令牌校验结果的缓存时长。设 0 = 每次回源 |
onCenterUnavailable |
deny |
中心不可达且本地无缓存时:deny 拒绝 / stale 放行 |
可用性设计:本地验签不依赖账户中心;版本校验优先用缓存。 因此账户中心短暂不可达时,已登录用户不受影响——只有"缓存刚好过期又要回源"的少数请求会受影响。
区分两类失败(重要):
- 拿不到 JWKS(中心不可达)→
CENTER_UNAVAILABLE - 拿到了 JWKS 但没有这把 kid(可能是伪造)→
INVALID_TOKEN
开发
pnpm install
pnpm --filter @abds10/capability-auth run build
pnpm --filter @abds10/capability-auth test # 26 项断言
测试不 mock 内部模块:用 jose 生成真的 Ed25519 密钥、签真的 JWT,
并用一个内存里的假账户中心提供 /jwks.json 等端点,因此覆盖的是真实代码路径。
Dependencies
Dependencies
| ID | Version |
|---|---|
| @abds10/contracts | ^1.0.0 |
| jose | ^5.9.6 |
Development Dependencies
| ID | Version |
|---|---|
| @types/node | ^22 |
Peer Dependencies
| ID | Version |
|---|---|
| next | >=15 |
鄂公网安备42010302002985号