• Joined on 2026-08-25

@abds10/capability-auth (1.0.4)

Published 2026-10-01 15:26:39 +00:00 by deploy

Installation

@abds10:registry=https://git.abds10.cn/api/packages/deploy/npm/
npm install @abds10/capability-auth@1.0.4
"@abds10/capability-auth": "1.0.4"

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
Details
npm
2026-10-01 15:26:39 +00:00
23
UNLICENSED
39 KiB
Assets (1)
Versions (6) View all
1.0.5 2026-10-10
1.0.4 2026-10-01
1.0.3 2026-09-10
1.0.2 2026-09-10
1.0.1 2026-09-10