Kanidm OAuth2 Refresh Token 设计解析:NIB 机制、重放检测与复制一致性
后端认证鉴权安全【免费下载链接】kanidmKanidm: A simple, secure, and fast identity management platform项目地址https://gitcode.com/gh_mirrors/ka/kanidm点击查看免费下载本文围绕 Kanidm 身份管理平台中 OAuth2 刷新令牌refresh token的官方设计文档展开深入剖析 Kanidm 如何通过「Not Issued BeforeNIB」时间戳机制实现刷新令牌的at most once语义、会话吊销的快速传播以及在多副本复制环境下的最终一致性保障。读完本文你将掌握 Kanidm OAuth2 令牌体系中访问令牌与刷新令牌的完整生命周期、重放攻击的检测与处置流程、失效令牌的清理策略并能对照仓库源码与测试用例理解每个设计决策的落地实现。背景为什么 OAuth2 令牌需要定期报到Kanidm 早期的认证会话因令牌缺乏权限分离privilege separation会话时长被限制在 1 小时。在实现权限分离后会话时长被延长到 8 小时未来还可能继续增加。但这对 OAuth2 提出了一个挑战OAuth2 访问令牌access token在过期前都被视为有效。如果直接签发有效期 8 小时甚至更长的访问令牌将带来两个严重问题令牌滥用窗口过长恶意用户rogue users可以在很长一段时间内持续使用令牌直到被强制重新认证吊销传播延迟当某个账户必须被强制终止时该用户仍可访问各个 OAuth2 应用长达 8 小时或更久。为此设计文档给出的结论是OAuth2 令牌必须周期性报到check in以重新确认会话仍然有效。这就是引入访问令牌 刷新令牌两层结构的原因访问令牌生命周期很短设计提案为 15 分钟由依赖方relying party应用直接使用刷新令牌应用必须定期用刷新令牌回 Kanidm 换取新的访问令牌而 Kanidm 在这一步可以核对底层会话的真实有效性与吊销状态。于是每个 OAuth2 应用必须周期性报到才能让访问令牌保持存活而一旦会话被吊销最多只需要等待一个访问令牌生命周期15 分钟吊销即可传播到所有应用。这一设计在仓库源码中得到了完全一致的落地server/lib/src/constants/mod.rs第 188 行定义了pub const OAUTH2_ACCESS_TOKEN_EXPIRY: u32 15 * 60;即访问令牌固定为 15 分钟同文件第 184 行定义了默认刷新令牌生命周期pub const OAUTH_REFRESH_TOKEN_EXPIRY: u32 3600 * 16;16 小时且刷新令牌可被单个应用配置覆盖见下文刷新令牌生命周期可配置一节。风险分析刷新令牌必须防住的两类滥用令牌增殖Token Proliferation刷新令牌会被提交到依赖方服务器即 Kanidm 的 OAuth2 授权端点换取访问令牌以及一个可选的新刷新令牌。正因为如此攻击者理论上可以多次提交同一个刷新令牌从而在系统之外增殖出大量额外的刷新令牌与访问令牌。设计文档强调阻止这种行为对于限制令牌使用范围、实现有效监控与吊销至关重要。这对应 OAuth 安全主题草案draft-ietf-oauth-security-topics第 2.2.2 节的要求。旧刷新令牌的至少一次at most once语义已交换过的旧刷新令牌不能再被使用。如果不强制这一点即使关联的访问令牌早已过期数小时、刷新令牌也已被使用过攻击者仍可用旧刷新令牌重新获得会话访问权。设计文档明确将其与draft-ietf-oauth-security-topics的refresh_token_protection一节对齐。客户端绑定刷新令牌只能由与其关联的客户端应用使用。Kanidm 通过既有的客户端授权检查client authorisation checks严格强制这一点对应 RFC 6749 第 10.4 节的要求。这一约束在源码中同样有明确实现server/lib/src/idm/oauth2.rs的check_oauth2_token_refresh第 1630 行起在解包刷新令牌后会核对令牌所属的 OAuth2 资源服务器o2rs与客户端授权信息再决定是否放行测试用例test_idm_oauth2_refresh_token_invalid_client_authz第 7281 行专门验证了使用错误的 client id / 授权信息进行刷新会被拒绝。核心设计以 NIB 时间戳实现 at most once单服务器场景下的 NIB 机制设计文档给出了核心设计图其要点是为每个会话关联一个 not issued beforeNIB时间戳。刷新令牌要有效其IATissued at签发时间必须大于或等于会话当前的 NIB。┌─────────────────────────────────────────┐ │Kanidm │ │ │ │ ┌─────────┐ ┌─────────┐ │ │ │ │ │ │ │ │ │ Session │ 3. Update │ Session │ │ │ │ NIB 1 │─────NIB───────▶│ NIB 2 │ │ │ └─────────┘ └─────────┘ │ │ │ │ │ └───┼───────────────────────────┼─────────┘ ┌────┘ ▲ ┌────┘ │ │ │ 1. Issued │ 4. Issued │ │ │ ▼ │ ▼ ┌───────┐ │ ┌───────┐ │Access │ │ │Access │ │ │ │ │ │ │Refresh│──2. Refresh──┘ │Refresh│ │ IAT 1 │ │ IAT 2 │ └───────┘ └───────┘流程解读首次签发授权码交换成功后Kanidm 签发第一组令牌Access RefreshIAT 1并在会话记录上记录issued_at即 NIB 1首次刷新客户端用 IAT 1 的刷新令牌换取新令牌推进 NIBKanidm 验证通过后把会话的issued_at推进到当前时间NIB 2同时签发第二组令牌IAT 2重用检测如果 IAT 1 的刷新令牌在第二次签发后被再次使用由于 NIB 已推进到 2而IAT 1 NIB 2条件IAT NIB不成立——这必然意味着该刷新令牌此前已被用于交换即检测到重用。NIB 在源码中的落地这套设计在server/lib/src/idm/oauth2.rs中有完整实现。刷新时check_oauth2_token_refresh在解密并校验令牌后会执行以下关键步骤第 1693-1732 行// Check the not issued before of the session relative to this refresh iat let oauth2_session entry .get_ava_as_oauth2session_map(Attribute::OAuth2Session) .and_then(|map| map.get(session_id)) .ok_or_else(|| { /* No OAuth2 session found */ Oauth2Error::InvalidGrant })?; // If the refresh token was issued previous to the time listed in our oauth2_session // this indicates session desync / replay. We must nuke the session at this point. if iat oauth2_session.issued_at.unix_timestamp() { security_info!(?session_id, Attempt to reuse a refresh token detected, destroying session); // Revoke it: remove the OAuth2 session from the account entry let modlist ModifyList::new_list(vec![Modify::Removed( Attribute::OAuth2Session, PartialValue::Refer(session_id), )]); self.qs_write.internal_modify(/* ... */)?; return Err(Oauth2Error::InvalidGrant); }注意这里比较的正是iat oauth2_session.issued_atissued_at即设计文档中的 NIB 值。一旦判定为重放Kanidm 会直接删除账户上的 OAuth2 会话记录并返回InvalidGrant——这正是检测到重用即销毁会话的实现。而每次刷新成功后generate_access_token_response第 2009 行起在签发新令牌的同时会把会话的issued_at更新为当前时间第 2197-2228 行即推进 NIB// Write the session to the db even with the refresh path, we need to do // this to update the not issued before time. let session Value::Oauth2Session( session_id, Oauth2Session { parent: parent_session_id, state: SessionState::ExpiresAt(odt_refresh_expiry), issued_at: odt_ct, rs_uuid: o2rs.uuid, }, ); // NOTE: Oauth2_session has special handling that allows update in place // without the remove step needing to be carried out. let modlist ModifyList::new_list(vec![Modify::Present(Attribute::OAuth2Session, session)]); self.qs_write.internal_modify(/* ... */)?;这里Oauth2Session结构体的issued_at字段承担了 NIB 的角色会话状态被设为SessionState::ExpiresAt(odt_refresh_expiry)使 OAuth2 会话的生命周期与刷新令牌生命周期而非访问令牌生命周期绑定。复制环境下的稳定性最终一致性与 NIB 合并Kanidm 支持多副本部署。设计文档特别论证了 NIB 机制在复制环境下即便漏掉一次会话更新也是稳定且正确的2. ┌───────────────────────Replicate────────────────┐ │ │ ┌───────┼─────────────────────────────────┐ ┌──────┼──────────────────────────────────┐ │Kanidm │ │ │Kanidm│ │ │ ┌─────────┐ ┌─────────┐ │ │ ┌─────────┐ ┌─────────┐ │ │ │ Session │ 4. Update │ Session │ │ │ │ Session │ 7. Update │ Session │ │ │ │ NIB 1 │─────NIB───────▶│ NIB 2 │ │ │ │ NIB 1 │ ─────NIB───────▶│ NIB 3 │ │ │ └─────────┘ └─────────┘ │ │ └─────────┘ └─────────┘ │ │ │ │ │ │ ▲ │ │ └───┼───────────────────────────┼─────────┘ └──────┼────────────────────────┼─────────┘ ┌────┘ ▲ ┌────┘ │ ┌────┘ │ │ │ │ │ 1. Issued │ 5. Issued │ 8. Issued │ │ │ │ │ ▼ │ ▼ │ ▼ ┌───────┐ │ ┌───────┐ │ ┌───────┐ │Access │ │ │Access │ │ │Access │ │ │ │ │ │ │ │ │ │Refresh│──3. Refresh──┘ │Refresh│ │ │Refresh│ │ IAT 1 │ │ IAT 2 │─────6. Refresh──────────┘ │ IAT 3 │ └───────┘ └───────┘ └───────┘示例场景第一台 Kanidm 服务器上的会话 NIB 1 被复制到第二台服务器但 NIB 2 的更新尚未复制过去此时若把 IAT 2 的刷新令牌提交给第二台服务器由于IAT 2 NIB 1它仍然有效可以正常刷新这次刷新会促使会话继续推进到 NIB 3当复制恢复时NIB 3 的会话将优先于此前的 NIB 2 会话NIB 更大的更新胜出。结论复制滞后只会在非常短的时间窗口内允许旧的访问令牌在第二台副本上使用。由于该基础设施位于负载均衡器之后、且不受攻击者操控利用这一窗口攻击的难度极高、收益极低属于可接受的风险。这正是 NIB 单调递增特性带来的容错优势——即使部分副本漏掉了中间状态最终一致状态依然安全收敛。攻击检测重用即全局吊销会话设计文档引用draft-ietf-oauth-security-topics第 4.14.2 节当检测到刷新令牌重用reuse时应取消该会话的所有令牌迫使用户重新发起授权码流程。Kanidm 的实现在这一点上比仅拒绝更进一步——前面已经看到check_oauth2_token_refresh在检测到iat issued_at时会删除整个 OAuth2 会话记录并返回InvalidGrant。这意味着不仅本次刷新被拒绝与该会话绑定的所有令牌当前访问令牌与任何衍生刷新令牌也随之失效用户必须走完整的授权码流程重新建立会话。对应的测试test_idm_oauth2_refresh_token_reuse_invalidates_session第 7359 行完整验证了这一行为// Now use it again. - this will cause an error and the session to be terminated. let ct Duration::from_secs(TEST_CURRENT_TIME 2); // ... 使用第一次签发时得到的 refresh_token 再次刷新 ... let access_token_response_3 idms_prox_write .check_oauth2_token_exchange(client_authz, token_req, ct) .unwrap_err(); assert_eq!(access_token_response_3, Oauth2Error::InvalidGrant); // The session should be invalid at this point. let valid entry .get_ava_as_oauth2session_map(Attribute::OAuth2Session) .and_then(|sessions| sessions.first_key_value()) .map(|(_, session)| !matches!(session.state, SessionState::RevokedAt(_))) .unwrap(); assert!(!valid);此外test_idm_oauth2_refresh_token_divergence第 7437 行专门覆盖了会话分叉场景先不提交事务地使用 refresh 1 生成 refresh 2再使用 refresh 2 刷新验证最终会话状态与 NIB 推进的一致性——这正是复制/异步写路径下可能出现的真实情况的回归测试。失效刷新令牌与not after策略令牌自身的过期字段OAuth security topics第 4.14.2 节同时指出不活跃inactive的令牌应在一定时间后被作废。在刷新令牌这一层Kanidm 通过在加密刷新令牌内部携带一个exp字段来实现Oauth2TokenType::Refresh { scopes, parent_session_id, session_id, exp, uuid, iat, nbf, nonce, auth_time }见server/lib/src/idm/oauth2.rs第 2158-2168 行的构造以及proto/src/oauth2.rs中的类型定义。刷新时第一步就是校验exp ct则返回InvalidGrant第 1674-1677 行。刷新令牌是一个 JWE 加密的紧凑串在域版本domain level≥ 1.12 时使用jwe_a256gcm_encryptAES-256-GCM否则回退到jwe_a128gcm_encryptAES-128-GCM——见第 2177-2195 行。访问令牌则是 RFC 9068 规范的atjwtJWS 签名ES256 或 RS256其中携带scope、nonce、session_id、parent_session_id等扩展声明见OAuth2RFC9068Token与OAuth2RFC9068TokenExtensionsproto/src/oauth2.rs第 218-257 行。服务端的 not after 参数与会话清理设计文档提出服务端需要一个随令牌活动而更新的not after 参数以追踪最后一次活动时间同时需要不活跃会话清理并建议将其扩展进已存在的会话一致性插件session consistency plugin。仓库中这一插件确实存在并承担了该职责server/lib/src/plugins/session.rs定义了SessionConsistency插件注册名为plugin_session_consistency并通过server/lib/src/plugins/mod.rs的pre_modify/pre_batch_modify钩子挂入写入事务。其modify_inner按顺序执行三类清理第 43-184 行凭据被移除则吊销会话若账户上的主凭据密码、passkey、attested passkey、OAuth2 账户凭据 UUID已不存在则移除对应的用户认证会话过期 UAT 清理SessionState::ExpiresAt(exp)且exp curtime的用户认证会话被移除过期/孤儿 OAuth2 会话清理已过期的 OAuth2 会话被移除若父会话不存在且已超过宽限期grace window则移除孤儿 OAuth2 会话。其中宽限期由proto/src/constants.rs第 55 行的pub const AUTH_TOKEN_GRACE_WINDOW: Duration Duration::from_secs(5 * 60);5 分钟定义用于容忍异步/复制造成的父会话可见性延迟。插件内对应测试test_session_consistency_oauth2_expiry_cleanup、test_session_consistency_oauth2_removed_by_parent、test_session_consistency_oauth2_grace_window_past分别覆盖了这三类场景。由于刷新令牌的每一次使用本身就是活动信号会同步推进会话的issued_at与过期时间设计文档明确指出不需要额外的信令机制来上报活跃度。会话有效性复核链路刷新令牌换发访问令牌时Kanidm 会复核底层会话的真实状态。check_oauth2_token_refresh的核心调用链如下解析并解密 JWE确认是Oauth2TokenType::Refresh而非访问令牌用访问令牌冒充刷新令牌会被拒绝第 1659-1662 行校验exp是否已过期调用check_oauth2_account_uuid_valid(uuid, session_id, parent_session_id, iat, ct)第 1682 行——该调用同时校验**父会话用户认证会话**与OAuth2 会话的有效性账户是否有效、父会话是否被吊销、OAuth2 会话是否仍在宽限期内等server/lib/src/idm/server.rs中相关实现按 NIB 规则检测重放校验请求的 scope 是原 scope 的子集否则返回InvalidScope第 1734-1749 行调用generate_access_token_response签发新令牌并推进 NIB。值得注意的实现细节源码第 2021-2030 行的注释generate_access_token_response中令牌的过期时间刻意不引用会话的过期时间——因为无论是授权码交换路径还是刷新路径进入该函数前会话的有效性已被验证过这里签发的exp纯粹描述令牌自身的寿命。同时注释明确指出刷新令牌生命周期可配置而访问令牌生命周期不可配置因为 OAuth2 没有内建的吊销机制必须通过频繁换发访问令牌来反复验证会话状态。刷新令牌生命周期可配置每个 OAuth2 资源服务器应用可以设置自己的刷新令牌生命周期Oauth2RS结构体中的refresh_token_expiry: u32字段第 552 行从账户/应用条目的Attribute::OAuth2RefreshTokenExpiry读取第 974-975、1041 行签发刷新令牌时refresh_expiry iat o2rs.refresh_token_expiry第 2033 行。未配置时使用默认值OAUTH_REFRESH_TOKEN_EXPIRY 3600 * 1616 小时。测试test_idm_oauth2_refresh_token_basic第 7027 行中的一段第 7133-7167 行专门验证了自定义刷新时间后新换发的令牌采用更新后的生命周期。会话过期后刷新令牌失效刷新令牌虽然有自己的exp但设计上会话时长仍然兜底约束测试test_idm_oauth2_refresh_token_oauth2_session_expired第 7230 行验证了当底层 OAuth2 会话父会话过期或缺失时即使刷新令牌本身未到期刷新也会被拒绝——因为check_oauth2_account_uuid_valid找不到有效会话。这与设计文档中刷新令牌必须以底层会话有效性为前提的定位一致。异步写路径的取舍原设计的遗留问题设计文档在 Questions 一节提出了一个值得关注的工程权衡当前授权码授权authorisation code grant与会话的记录是**异步async**进行的。文档作者认为刷新路径也应保持一致——即刷新令牌已签发、但会话记录写入存在轻微延迟。鉴于未来的复制机制本就依赖异步/最终一致性这不会造成额外影响最多带来客户端在更新过程中的轻微延迟。但也不希望异步/延迟动作队列delayed action queues过满或过载。文档认为队列监控/积压问题可作为一个独立问题另行处理。从源码看这一异步性体现在会话写入通过self.qs_write.internal_modify(...)在事务中完成而刷新令牌的验证依赖事务提交后可见的issued_attest_idm_oauth2_refresh_token_divergence中特意不提交事务drop(idms_prox_write)来模拟未提交/异步分叉场景正是对这类一致性问题的事先防御。总结设计要点速览设计目标Kanidm 实现源码位置访问令牌短生命周期固定 15 分钟OAUTH2_ACCESS_TOKEN_EXPIRY 15 * 60server/lib/src/constants/mod.rs刷新令牌默认生命周期16 小时可被单应用OAuth2RefreshTokenExpiry覆盖server/lib/src/constants/mod.rs、server/lib/src/idm/oauth2.rsat most once会话issued_atNIB单调推进iat issued_at判为重放server/lib/src/idm/oauth2.rs重用检测处置删除 OAuth2 会话并返回InvalidGrant强制重新授权server/lib/src/idm/oauth2.rs客户端绑定刷新时必须携带合法客户端授权否则拒绝server/lib/src/idm/oauth2.rs失效令牌清理plugin_session_consistency清理过期/孤儿 OAuth2 会话宽限期 5 分钟server/lib/src/plugins/session.rs、proto/src/constants.rs令牌格式访问令牌为 RFC 9068atjwtJWS刷新令牌为 JWE 加密proto/src/oauth2.rs、server/lib/src/idm/oauth2.rs会话复核刷新前校验父会话与 OAuth2 会话双重有效性server/lib/src/idm/oauth2.rs总体而言Kanidm 的刷新令牌设计用一个单调推进的 NIB 时间戳同时解决了三个问题让访问令牌保持短生命周期以快速传播吊销、让刷新令牌具备 at most once 语义以阻止增殖、让复制环境下的最终一致性自然收敛。这套机制既符合 OAuth2 安全最佳实践RFC 6749 与 OAuth security topics也在源码与测试中得到了严谨的实现与验证可作为自建 OAuth2/OIDC 服务时刷新令牌安全设计的参考范本。赞分享后端认证鉴权安全【免费下载链接】kanidmKanidm: A simple, secure, and fast identity management platform项目地址https://gitcode.com/gh_mirrors/ka/kanidm点击查看免费下载相关推荐BiliBiliToolPro 使用教程B 站自动签到与多账号管理的快速上手指南BiliBiliToolPro 使用教程B 站自动签到与多账号管理的快速上手指南 BiliBiliToolPro 是一个基于 .NET 开发的 B 站bil后端任务调度工作流自动化Kanidm 跨域信任Trust机制设计解析基于分数复制的身份联邦方案Kanidm 跨域信任Trust机制设计解析基于分数复制的身份联邦方案 Kanidm 的跨域信任Trust是一项将独立 Kanidm 实例中的用户与群后端认证鉴权安全Kanidm 架构设计解析Schema 引用类型Reference Types与引用完整性机制Kanidm 架构设计解析Schema 引用类型Reference Types与引用完整性机制 Kanidm 的身份数据模型中对象之间需要相互引用——最后端认证鉴权安全创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

Cats Free Monad 实战指南:用嵌入式 DSL 构建可组合、可重定向的纯函数式程序

Cats Free Monad 实战指南:用嵌入式 DSL 构建可组合、可重定向的纯函数式程序

后端 【免费下载链接】cats Lightweight, modular, and extensible library for functional programming. 项目地址: https://gitcode.com/gh_mirrors/ca/cats 点击查看 免费下载 本文是 Cats 函数式编程库中 cats-free 模块的完整技术指南。自由单子(F…

2026/10/12 20:08:21 阅读更多 →
可靠性数据统计方法与R语言实战:从配套数据集到Weibull建模

可靠性数据统计方法与R语言实战:从配套数据集到Weibull建模

简介:《Statistical Methods for Reliability Data》配套数据集面向可靠性建模学习者和从业者,是这本经典著作的实操补充。包内围绕寿命分布、生存分析、故障率函数、可靠性增长、多组件系统可靠性、寿命试验设计与统计推断等核心知识点,提供…

2026/10/12 20:07:21 阅读更多 →
AI编程agent失控?用最小规格驱动工作流守住代码边界

AI编程agent失控?用最小规格驱动工作流守住代码边界

我本来是想抄作业的。Spec Kit、OpenSpec、Superpowers 这三个名字,我在搜索框里来回扫了不止一遍。原因很简单:最近一段时间的 AI 编程 agent 越来越难控制,改一个登录模块,它能顺手把我另一个文件的变量名也改了;说好…

2026/10/12 20:07:21 阅读更多 →

最新新闻

虚拟内存深度解析:从地址翻译到性能调优的工程实践

虚拟内存深度解析:从地址翻译到性能调优的工程实践

1. 从一个“内存不够用”的深夜说起如果你写过稍微大一点的程序,或者同时开过十几个浏览器标签页、几个IDE、一个数据库再加一个本地服务,大概率见过系统弹出来的“内存不足”提示,或者眼睁睁看着某个进程被系统强制结束。这时候有人会告诉你…

2026/10/12 22:38:20 阅读更多 →
全球地区维表设计:国家省市三级建模与数据清洗导入避坑

全球地区维表设计:国家省市三级建模与数据清洗导入避坑

简介:一套包含全球主要国家、省/州及城市的地区数据库,以中英文双版本提供,适用于Web开发、数据分析、地图应用及行政区划映射场景。数据采用XML格式组织,结构清晰,便于直接解析和二次加工;中英文文件可独立…

2026/10/12 22:38:20 阅读更多 →
RAGFlow部署实战:Docker容器编排与systemd托管配置指南

RAGFlow部署实战:Docker容器编排与systemd托管配置指南

简介:面向具备Docker基础、希望快速部署或深入调优RAGFlow的技术人员,PDF文档系统讲解基于Docker部署RAGFlow时的关键配置:.env环境变量文件负责Elasticsearch、MySQL、MinIO、Redis等服务的端口与密码设置;service_conf.yaml.tem…

2026/10/12 22:38:19 阅读更多 →
2024全国职业院校技能大赛移动应用开发赛题拆解与Android实战指南

2024全国职业院校技能大赛移动应用开发赛题拆解与Android实战指南

简介:2024年全国职业院校技能大赛移动应用设计与开发赛项高职组赛题解析,以PDF文档形式呈现,共一个文件,大小约五百二十八KB,面向参赛选手、指导教师及移动应用开发学习者。文档完整收录竞赛试题零二卷,清晰…

2026/10/12 22:38:18 阅读更多 →
LL(1)语法分析器实现指南:从FIRST集与FOLLOW集到预测分析表

LL(1)语法分析器实现指南:从FIRST集与FOLLOW集到预测分析表

简介:编译原理课程中的LL(1)语法分析器实验,往往需要同时完成文法设计、预测分析表构造与输入串判别等多个环节。这套资源面向正在学习自顶向下语法分析的本科生,围绕实验二提供了一个完整方案,内含源代码、可执行程序、实验报告、…

2026/10/12 22:38:17 阅读更多 →
Python实现PL0编译器:从词法分析到P-code生成的完整课设指南

Python实现PL0编译器:从词法分析到P-code生成的完整课设指南

简介:面向南京航空航天大学计算机专业学生、也适合其他编译原理初学者的课程设计资源,以精简的PL0教学语言为载体,使用Python实现从词法分析、语法分析到语义分析与后端代码生成的完整编译器。压缩包共8个文件,主体是5个Python脚本…

2026/10/12 22:37:16 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

在数码相机、高清显示屏与现代矢量图形技术高度发达的今天,画面可以做到绝对的锐利、平滑与无瑕。然而,当一张秋日手账插画或拍立得照片过于“平整无瑕”时,往往会散发出一种冰冷生硬的“数码塑料感(Digital Plasticity&#xff0…

2026/10/12 0:00:59 阅读更多 →
活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

在现代网页与移动端设计中,横排(Horizontal Layout)早已经成为了绝对的主流。然而,当我们翻开泛黄的线装古籍、宋版木刻诗集,或是欣赏一张茶道雅集的手写便签时,那种**自上而下纵向书写、自右向左逐列铺展&…

2026/10/12 0:00:59 阅读更多 →
周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

每到周日的晚上八点到十点,很多人心里都会悄悄亮起一盏警示灯。 在心理学上,这种现象有一个专门的称谓——“周日夜晚焦虑症(Sunday Scaries)”。明天又是周一,闹钟又要重新在七点响彻卧房;脑海里仿佛有一个…

2026/10/12 0:00:59 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →