- 后端
- 认证鉴权
- 单点登录
【免费下载链接】cas
Apereo CAS - Identity & Single Sign On for all earthlings and beyond.
JSON 是 Apereo CAS 密码管理(Password Management)功能支持的最简单账户存储后端:账户与密码被存放在一个静态的 JSON 资源文件中,通过cas.authn.pm.json.location一个配置项即可接入。本文以 Password-Management-JSON.md 为骨架,结合仓库中cas-server-support-pm-core与cas-server-support-pm模块的源码与测试,完整讲解 JSON 文件格式、开启方式、可用配置参数、底层工作机理及其适用边界,让读者既能快速上手,也能理解其内部实现。
JSON 后端的定位与适用场景
CAS 官方文档对 JSON 存储给出了明确的定位:账户与密码保存在一个静态的、精简的 JSON 资源中,其位置通过 CAS 配置告知系统。这一选项最适合开发、测试与演示环境,不适合生产环境。
从仓库实现看,JSON 后端对应的服务类为JsonResourcePasswordManagementService,位于 support/cas-server-support-pm-core/src/main/java/org/apereo/cas/pm/impl/JsonResourcePasswordManagementService.java,它在 CAS 的密码管理存储清单(JSON、Groovy、LDAP、JDBC、REST、Custom,见 Password-Management.md 的 Storage 小节)中属于最简单的实现:不需要数据库、目录服务或外部 HTTP 服务,只要一个可读(必要时可写)的 JSON 文件即可支撑忘记密码、修改密码、密保问题等基础流程。
开启 JSON 密码管理:依赖与配置
密码管理整体功能需要cas-server-support-pm-webflow模块(在 WAR overlay 中加入该依赖即可启用相关 Webflow)。在此基础上,JSON 后端仅需在application.properties(或 YAML)中配置两个属性:
# 开启密码管理核心功能(必填) cas.authn.pm.core.enabled=true # 指定 JSON 账户文件的位置(必填) cas.authn.pm.json.location=file:/etc/cas/config/pm-accounts.jsoncas.authn.pm.core.enabled在配置模型 PasswordManagementCoreProperties.java 中被标注为@RequiredProperty,即密码管理功能的总开关。cas.authn.pm.json.location对应配置模型 JsonPasswordManagementProperties.java,它继承自 SpringResourceProperties.java,location同样为@RequiredProperty。该属性支持 Spring 资源定位语法:既可以是file:/绝对路径,也可以是classpath:xxx.json或https://...等 URL。
值得注意的是,CAS 采用按需装配策略:只有在环境中检测到cas.authn.pm.json.location属性存在时,才会创建JsonResourcePasswordManagementService这个 Bean。这一判断逻辑位于 CasPasswordManagementAutoConfiguration.java:
return () -> BeanSupplier.of(PasswordManagementService.class) .when(BeanCondition.on("cas.authn.pm.json.location").exists().given(applicationContext.getEnvironment())) .supply(() -> new JsonResourcePasswordManagementService(passwordManagementCipherExecutor, casProperties, location, passwordHistoryService)) .otherwiseProxy() .get();即:配置了cas.authn.pm.json.location,JSON 后端即被激活;未配置则返回代理占位,不会影响其他存储后端的装配。该服务还会注入passwordManagementCipherExecutor(用于重置令牌的加解密)和passwordHistoryService(用于密码历史校验)。
相关的可选核心参数
围绕密码管理核心功能,PasswordManagementCoreProperties.java 还提供了以下可选参数:
| 配置项 | 默认值 | 说明 |
|---|---|---|
cas.authn.pm.core.enabled | 无(必填) | 是否启用密码管理功能 |
cas.authn.pm.core.auto-login | false | 密码修改成功后是否自动完成登录 |
cas.authn.pm.core.password-policy-pattern | ^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&])[A-Za-z\d$@$!%*?&]{8,10} | 新密码必须满足的正则策略:默认要求 8~10 位、至少 1 个大写、1 个小写、1 个数字和 1 个特殊字符 |
cas.authn.pm.core.password-policy-character-set | abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789![]{}()%&*$#^<>~@\| | CAS 生成/建议新密码时使用的字符集 |
cas.authn.pm.core.password-policy-password-length | 10 | CAS 建议密码的默认长度 |
这些参数与存储后端无关,JSON 后端同样适用;例如仓库测试用例 JsonResourcePasswordManagementServiceTests.java 中就用cas.authn.pm.core.password-policy-pattern=^Test1.+验证了密码策略校验行为。
JSON 账户文件格式详解
官方文档给出的账户文件结构如下(顶层是一个以用户名为键的映射):
{ "casuser" : { "email" : "casuser@example.org", "password" : "p@ssw0rd", "phone" : "1234567890", "status": "OK", "securityQuestions" : { "question1" : "answer1", "question2" : "answer2" } } }每个账户对象对应源码中JsonBackedAccount内部类(JsonResourcePasswordManagementService.java)的字段,两者一一对应:
| JSON 字段 | 类型 | 含义与用途 |
|---|---|---|
email | String | 账户邮箱,用于"忘记用户名"(findUsername)与找回/重置流程中的邮件投递 |
password | String | 明文密码。源码中密码以明文 String 直接存放于 JSON,这是其不适合生产环境的重要原因 |
phone | String | 手机号,用于短信通知类流程(findPhone) |
status | String | 账户状态。源码中unlockAccount会检测locked状态并将其改写为OK,用于账户解锁场景 |
securityQuestions | Map<String, String> | 密保问题与答案的键值对,用于重置密码时的身份校验与更新 |
仓库测试资源 support/cas-server-support-pm/src/test/resources/jsonResourcePassword.json 提供了与此格式完全一致的实例,可作为编写自定义账户文件的直接模板。
一个值得注意的细节:HJSON 解析
JsonResourcePasswordManagementService在读取文件时并非直接使用标准 JSON 解析,而是先经JsonValue.readHjson(reader)处理后再交给 Jackson 反序列化(见 JsonResourcePasswordManagementService.java):
val personList = new TypeReference<Map<String, JsonBackedAccount>>() {}; jsonBackedAccounts = MAPPER.readValue(JsonValue.readHjson(reader).toString(), personList);这意味着账户文件实际上按HJSON(Human JSON)语法解析,允许在文件中书写#注释、省略多余的引号或容忍尾随逗号,便于人工维护。
从源码看 JSON 后端的能力边界
JsonResourcePasswordManagementService继承自 BasePasswordManagementService.java,后者实现了令牌创建/解析与带审计、密码历史检查的通用change流程,前者则逐一实现与 JSON 文件交互的具体操作:
- 修改密码:
changeInternal先校验新密码非空、与确认密码一致、且用户存在于文件中,随后更新内存中的账户并调用writeAccountToJsonResource()写回文件。 - 查找邮箱:
findEmails按用户名返回邮箱集合(用于发送重置/找回邮件)。 - 查找手机号:
findPhone按用户名返回手机号。 - 查找用户名:
findUsername按邮箱反向定位用户名,支撑"忘记用户名"功能。 - 密保问题:
getSecurityQuestions返回账户的密保问题映射;updateSecurityQuestions支持用户自助更新密保问答并写回文件。 - 账户解锁:
unlockAccount将status为locked的账户改写为OK并持久化。
这些能力在 JsonResourcePasswordManagementServiceTests.java 中均有对应测试用例:例如verifyUserEmailCanBeFound验证按用户名找回邮箱、verifyUserCanBeFound验证按邮箱找回用户名、verifyUserPhoneCanBeFound验证手机号查询、verifyUnlock验证账户解锁、verifyUserQuestionsCanBeFound与verifySecurityQuestions验证密保问题的读取与更新、verifyUserPasswordChange/verifyUserPasswordChangeFail验证密码修改的成功与失败分支、verifyPasswordValidationService验证密码策略正则的生效,以及verifyToken验证重置令牌的创建与解析。
密码修改的写回机制:classpath 资源只读
writeAccountToJsonResource()的实现值得注意(JsonResourcePasswordManagementService.java):
MAPPER.writerWithDefaultPrettyPrinter().writeValue(jsonResource.getFile(), jsonBackedAccounts); readAccountsFromJsonResource();它调用jsonResource.getFile()把整个账户映射以美化格式写回原文件。这意味着:
- 读取(登录校验前的邮箱/密保查询等)可以走
classpath:等只读资源; - 写回(修改密码、更新密保、解锁账户)必须指向文件系统上真实可写的路径,否则
getFile()会失败。生产实践中应使用file:/...绝对路径并确保 CAS 进程对该文件有写权限; - 文件整体读写、无锁无事务,并发修改场景下可能互相覆盖,这也是官方将其限定为开发/测试/演示用途的原因之一。
通用流程的支撑:密码历史与审计
上层change方法(BasePasswordManagementService.java)带有@Audit(action = AuditableActions.CHANGE_PASSWORD, ...)审计注解,并在写回前先通过passwordHistoryService.exists(bean)检查新密码是否命中密码历史策略、写回后调用passwordHistoryService.store(bean)记录历史。也就是说,即使存储后端是 JSON,密码历史(Password-Management-History.md)与审计日志依然生效,只是密码历史本身需要另行配置存储位置。
密码重置令牌:JSON 后端同样支持
密码重置功能与存储后端解耦。BasePasswordManagementService中createToken/parseToken负责生成与校验重置令牌:
- 令牌本质是包含
jti、issuer(CAS 服务前缀)、audience、subject(用户名)、签发时间与过期时间的 JWT 风格声明集合,再经cipherExecutor编码(BasePasswordManagementService.java)。 - 解析时校验签发者、受众、subject 是否匹配,并可依据
cas.authn.pm.reset.include-server-ip-address、cas.authn.pm.reset.include-client-ip-address校验来源 IP,最后校验过期时间(BasePasswordManagementService.java)。 - 令牌有效期由
cas.authn.pm.reset.expiration控制,配置模型 ResetPasswordManagementProperties.java 中默认值为PT1M。
因此,即使用户账户存放在 JSON 文件中,忘记密码后通过邮件/短信发送重置链接、点击链接完成改密的完整闭环依然可用。更完整的重置流程可参考 Password-Management-Reset.md 与 Password-Management-ForgotUsername.md。
与其他存储后端的取舍
在 CAS 的密码管理存储选项中(Password-Management.md),JSON 是唯一"零依赖"的静态文件方案:相比 Password-Management-LDAP.md、Password-Management-JDBC.md 与 Password-Management-REST.md,它无需任何外部服务即可在数分钟内完成演示环境搭建;相比 Password-Management-Groovy.md 的脚本化实现,它无需编写脚本逻辑。但相应的代价是:明文密码、整文件读写、无并发控制,因此官方明确建议生产环境改用 LDAP/JDBC/REST 等后端,或用 Password-Management-Custom.md 对接自建账户管理应用。
小结:三分钟跑通 JSON 密码管理
- 在 WAR overlay 中加入
cas-server-support-pm-webflow依赖; - 编写
pm-accounts.json,顶层以用户名为键,账户内含email、password、phone、status、securityQuestions字段; - 配置
cas.authn.pm.core.enabled=true与cas.authn.pm.json.location=file:/.../pm-accounts.json; - 重启 CAS,即可体验忘记用户名、密保问答、重置密码与账户解锁等流程;源码与测试用例(JsonResourcePasswordManagementServiceTests.java)可作为理解每一步行为的最佳参考。
- 后端
- 认证鉴权
- 单点登录
【免费下载链接】cas
Apereo CAS - Identity & Single Sign On for all earthlings and beyond.
相关推荐
Audacity 免费音频编辑指南:降噪到导出 MP3 只要 10 分钟
Audacity 免费音频编辑指南:降噪到导出 MP3 只要 10 分钟 Audacity 是一款免费开源的音频编辑工具,录音、剪辑、降噪、混音、导出都在同一套
音频处理桌面应用音视频Apereo CAS OpenID Connect JWKS 存储之 REST 方案:接口契约、配置详解与源码解析
Apereo CAS OpenID Connect JWKS 存储之 REST 方案:接口契约、配置详解与源码解析 JWKS(JSON Web Key Set)
后端认证鉴权单点登录Apereo CAS 简易密码less认证存储(Simple Passwordless Authentication Storage)配置与源码解析
Apereo CAS 简易密码less认证存储(Simple Passwordless Authentication Storage)配置与源码解析 本文以 A
后端认证鉴权单点登录
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考