@alxia/ janus (英语)
身份、会话和权限 阿尔克夏, (中文(简体) ),
打开 @softistx/janus: 你的过程,
你的数据库。 在上下文中键入的用户, 会话 cookie 保存和
雅努斯的拒绝以他们的身份 和一个安全的身体来回应 没有
依赖性.
bun add @alxia/janus @softistx/janus @alxia/core
bun add -d typescript
@softistx/janus 是私人的,在 GitHub 包上。 在您的地图中绘制其范围
bunfig.toml 并导出一个读取软件包的符号(read:packages:
[install.scopes]
"@softistx" = { url = "https://npm.pkg.github.com/", token = "$GITHUB_TOKEN" }
镜子 @softistx/janus-hono数字 :
同样的饼干,同样的规则,同样的身体.
一个叫 janus API 而不是运行的 BFF @softistx/janus 自己,想要
@alxia/react-router/session。 。 。 .
使用量
import { alxia, validate } from '@alxia/core';
import { janusErrors, session } from '@alxia/janus';
import { createMemoryStores, janus, scryptHasher } from '@softistx/janus';
import { z } from 'zod';
const accounts = janus({
user: z.object({ email: z.email(), name: z.string() }),
password: { login: 'email' },
store: createMemoryStores(), // your database's adapter in production
hasher: scryptHasher(),
});
const SignIn = z.object({ email: z.string(), password: z.string() });
const app = alxia()
.use(janusErrors(), session(accounts)) // errors first, then the session: anonymous may sign in
.post('/signin', validate({ body: SignIn }), async ({ body, auth, reply }) => {
const signedIn = await accounts.signIn(body);
return reply.ok({ id: auth.send(signedIn).id }); // the token in the cookie
})
.post('/signout', async ({ auth, reply }) => reply.ok(await auth.signOut()))
.use(session(accounts, { required: true })) // the routes after it, and any unmatched request
.get('/me', ({ user, reply }) => reply.ok(user)); // user typed by the schema
janusErrors() 财务报告和审定财务报表 session() 是中间的软件. janusErrors() 答题
抛出的东西,你把它交给 use 在此之前 session()。 。 。 .
session(accounts, options?)
读完之后的路线 user, (中文(简体) ), session 财务报告和审定财务报表 auth与
required: true,匿名请求是401
{ error: 'unauthenticated' } 财务报告和审定财务报表 user 永远 null在应用程序上,a
需要的会话也会运行在请求上 没有路由匹配:匿名
请求去向缺失路径获得401,而不是404. 把它放进一个 group 改为
只保护一些路线,没有,它就是
null 对于匿名请求。 A 类 boolean 仅在运行时类型中知道
两者:401和a user 这可能是 null。 。 。 . type 缩小到一个用户
类型 janus()· ; device 命名设备饼干.
会议内容如下: Authorization: Bearer, (中文(简体) ), X-Session-Token,或
饼干 一个经过更新的路段 被再次作为饼干 之后的路线 -
只针对一个将它作为一个, 从来没有超过一个会议的请求
曲奇路线设定本身. 断电不是匿名的: 一个商店
无法回答 : STORE_FAILED,回答503 由 janusErrors()。 。 。 .
ctx.auth: 签名进出
签到就留在你身上 janus() 实例 accounts.signIn, (中文(简体) ), accounts.signUp, (中文(简体) ),
accounts.patient.signIn,代码,链接——和 ctx.auth 请求是否
部分,受约束:
ctx.auth. | |
|---|---|
send(signedIn) | 设置会话 cookie(和设备 cookie,带有 deviceToken)并返回用户: 符号从不在体内 |
signOut() | 取消请求的会话并清除其饼干,不管答案是什么 |
device | 设备饼干的值,或 null,用于 signIn(…, { device: ctx.auth.device }) 与 janus({ devices }) |
把签入路线放在后面 session(accounts) 这是 没有 要求:
后面 required: true匿名请求——任何签字者——是
401. 路线之外(工作、测试), sendSession(ctx, accounts, signedIn), (中文(简体) ),
signOut(ctx, accounts) 财务报告和审定财务报表 deviceOf(ctx) 是相同的功能,没有约束.
janusErrors(options?)
尝试/捕获中件: 每件 JanusError 被抛在后面——通过
session(), (中文(简体) ), permission() 或一条路线——以雅努斯的地位回答
以及一个拥有 code 只有客户可以采取行动
问题,最小长度,尝试左起,等待秒(与
Retry-After) (中文(简体) ). 永不入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出入出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出出. report(error, ctx) 实值
5xx的电话。 任何其它的事情,扔到中间的器皿上
这个 在应用程序上 alxia({ errors: 'problem' })它回答一个RFC 9457
相反,问题 code (a) 延长任期
所需经费 session()401岁和 permission()401、404和403跟着
该应用程序的格式也。 于 session(),它不会看到会议
STORE_FAILED:它首先进行,然后是观察员(logger(), (中文(简体) ),
secureHeaders()以便他们看见它的答复。 观察员解决
next() 没有吞下错误,所以 janusErrors() 之前,或
在此之前 createI18n()继续回答.
| 状态 | 代码 |
|---|---|
| 400个 | USER_INVALID, (中文(简体) ), PASSWORD_TOO_SHORT, (中文(简体) ), TOKEN_*. |
| 401 (中文(简体) ) | CREDENTIALS_INVALID, (中文(简体) ), CODE_INVALID |
| 403 (韩语) | USER_INACTIVE, (中文(简体) ), STEP_UP_REQUIRED |
| 404 (韩语) | NOT_FOUND |
| 409个 | LOGIN_TAKEN, (中文(简体) ), VERSION_CONFLICT, (中文(简体) ), SECOND_FACTOR_* |
| 429个 | MAIL_THROTTLED (单位:千美元)@softistx/janus 页:1 retryAfter 财务报告和审定财务报表 Retry-After |
| 500个 | PERMISSION_DEPTH |
| 501 (简体中文) | UNSUPPORTED |
| 第503条 | STORE_FAILED |
permission(access, permission, type, load, options?)
一个警卫 @softistx/janus/permissions: 运行后的路线,仅在
会议主题 user,或 options.subject(ctx) - 坚守
permission 在对象上 load 找到他们读作 object。 。 。 .
匿名是401,没有装入404,拒绝403,每个输入。 范围
带它 group数字 :
import { alxia } from '@alxia/core';
import { byParam, janusErrors, permission, session } from '@alxia/janus';
import { createMemoryStores, janus, scryptHasher } from '@softistx/janus';
import { createMemoryRelations, defineModel, permissions } from '@softistx/janus/permissions';
import { z } from 'zod';
const relations = createMemoryRelations();
const accounts = janus({
user: z.object({ email: z.email() }),
password: { login: 'email' },
store: createMemoryStores(),
relations,
hasher: scryptHasher(),
});
const access = permissions({
model: defineModel({
subjects: accounts.types,
types: { record: { related: { owners: ['user'] }, permits: { view: ['owners'] } } },
}),
store: relations,
});
const records = new Map([['r1', { id: 'r1', title: 'Blood test' }]]);
const findRecord = (id: string) => records.get(id) ?? null;
const app = alxia()
.use(janusErrors())
.use(session(accounts))
.group('/records/:id', (record) =>
record
.use(permission(access, 'view', 'record', byParam('id', findRecord)))
.get('/', ({ object, reply }) => reply(200, object)), // object: what findRecord found
);
byParam(name, find) 按路径参数加载。 允许
条件需要上下文 ctx: (ctx, object) => …时
准确的排序.
阅读应用程序的上下文
注释 load, (中文(简体) ), subject 或者说 ctx读取之前的参数
中间软件添加。 警卫需要它:一个不给它的应用程序
在警卫不能使用之前.
import type { BaseContext } from '@alxia/core';
const byTenant = permission(
access,
'view',
'record',
({ tenant, pathParams }: BaseContext & { tenant: { records: Map<string, { id: string; title: string }> } }) =>
tenant.records.get(pathParams['id'] ?? '') ?? null,
);
alxia().plugin(tenancy).use(session(accounts)).use(byTenant); // tenancy derives tenant
alxia().use(session(accounts)).use(byTenant); // a compile error: this app gives no `tenant`
附加说明的召回 any 不需要什么 所以警卫被拒
在每一个应用程序上:注释其内容,或者不附加说明.
API 密码
| 导出 | |
|---|---|
session(accounts, options?) | 中间软件 : user, (中文(简体) ), session, (中文(简体) ), auth |
SessionOptions | 其选项: type, (中文(简体) ), required, (中文(简体) ), device |
RequestAuth, (中文(简体) ), SessionOpened | 类型 ctx.auth数字 : send, (中文(简体) ), signOut, (中文(简体) ), device;和什么 send 选择: token, (中文(简体) ), session 财务报告和审定财务报表 user 从 @softistx/janus是因为 SignedIn,以及 deviceToken? |
sendSession, (中文(简体) ), signOut, (中文(简体) ), deviceOf, (中文(简体) ), sendDevice | 饼干,在路外 |
DEVICE_COOKIE | 设备饼干的名字, janus-device: 一个 @softistx/janus-hono 使用,所以一个设备记得另一个设备 |
SendSessionOptions, (中文(简体) ), DeviceCookieOptions | 其选项: device· ; name, (中文(简体) ), domain, (中文(简体) ), path, (中文(简体) ), sameSite, (中文(简体) ), secure, (中文(简体) ), maxAge |
janusErrors(options?) | 中间器皿:詹努斯的拒绝得到了回答; use 曾经 session() |
JanusErrors, (中文(简体) ), SessionMiddleware | 类型 janusErrors() 财务报告和审定财务报表 session() 生产 |
JanusErrorsOptions | 其选项: report,每个错误都拨打,回答 5xx |
permission(…), (中文(简体) ), byParam(…) | 警卫 |
PermissionOptions, (中文(简体) ), OptionsArgs | 其选项: subject, (中文(简体) ), ctx;和它的其他论点,在许可有条件时,选择权需要准确的;两者都取什么 subject 财务报告和审定财务报表 ctx 读取 BaseContext 作为最后两个默认参数 |
bodyOf, (中文(简体) ), statusOf | 拒绝的主体和地位 |
UnauthenticatedBody, (中文(简体) ), JanusErrorBody, (中文(简体) ), PermissionRefusedBody | 类型 |
UnauthenticatedProblem, (中文(简体) ), JanusErrorProblem, (中文(简体) ), PermissionRefusedProblem | 同样的答案 @alxia/core是因为 alxia({ errors: 'problem' }): RFC 9457问题, janusErrors()与它的 code 作为扩展的正文 |
Auth, (中文(简体) ), UserOfAuth, (中文(简体) ), ObjectData, (中文(简体) ), Awaitable | 页:1 janus() 此软件包的调用、 它所知道的用户、 应用程序加载时的对象、 值或承诺 |