ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Apereo CAS 基于 JDBC 的 Surrogate(代理)认证存储:配置、SQL 查询与源码实现

2026/9/25 2:31:19 拓冰建站 浏览量
Apereo CAS 基于 JDBC 的 Surrogate(代理)认证存储:配置、SQL 查询与源码实现 后端认证鉴权单点登录【免费下载链接】casApereo CAS - Identity Single Sign On for all earthlings and beyond.项目地址https://gitcode.com/gh_mirrors/ca/cas点击查看免费下载导读本文围绕 Apereo CAS 的JDBC Surrogate Authentication基于 JDBC 的代理认证存储展开讲解如何通过关系型数据库授权管理员用户冒充/代理其他用户登录的认证场景即所谓的sudo for the web。读完本文你将掌握 CAS 中cas-server-support-surrogate-authentication-jdbc模块的启用方式、两条核心 SQL 查询的编写规范与占位符语义、完整的配置参数清单以及底层SurrogateJdbcAuthenticationService的判定逻辑与通配符账户机制可直接照搬到自己的 CAS WAR overlay 中落地。关联文档Surrogate-Authentication-Storage-JDBC.md关于 Surrogate 认证的整体概念与其余存储方式Simple / JSON / LDAP / REST / Groovy / Custom可参见 Surrogate-Authentication.md。一、JDBC Surrogate 存储是什么Surrogate 认证又称 impersonation网页版 sudo的核心场景是管理员用户admin user先用自己的凭证完成认证再由 CAS 切换到另一个用户surrogate user的身份建立单点登录会话从而代表该用户登录应用、执行操作或排查问题。存储层负责回答两个问题某个管理员是否有权代理别人—— 通过资格查询eligibility query判定。某个管理员能代理哪些具体账号—— 通过账号列表查询accounts query拉取可被冒充的账号集合。JDBC 存储就是把这两个问题的答案放进关系型数据库的一张或多张表中由 CAS 通过JdbcTemplate执行 SQL 完成判定。CAS 官方将这种用法描述为Uses a JDBC-compatible database to authorize surrogate authentication relationships见 模块 build.gradle。二、启用方式在 WAR overlay 中引入依赖JDBC Surrogate 认证支持通过向 WAR overlay 添加以下依赖开启groupId 为org.apereo.casimplementation org.apereo.cas:cas-server-support-surrogate-authentication-jdbc该模块在仓库中的源码位于 support/cas-server-support-surrogate-authentication-jdbc其运行时依赖会自动带入cas-server-support-surrogate-authentication/surrogate-core/surrogate-api代理认证的核心抽象与基础服务cas-server-support-jdbc-drivers各类数据库 JDBC 驱动runtimeOnlycas-server-support-jpa-utilJpaBeans.newDataSource(...)等数据源装配工具。启用后CAS 会在CasFeatureModule.FeatureCatalog.SurrogateAuthentication特性开启且modulejdbc时自动装配相关 Bean见 CasSurrogateJdbcAuthenticationAutoConfiguration.java无需手工编写 Spring 配置。三、数据库表设计以测试用例为准仓库自带的单元测试 SurrogateJdbcAuthenticationServiceTests.java 给出了一个可直接参考的表结构CREATE TABLE surrogate_accounts ( id INT, username VARCHAR(255), -- 管理员admin用户名 surrogateAccount VARCHAR(255) -- 该管理员可代理的目标账号 ); INSERT INTO surrogate_accounts VALUES (100, casadmin, *); -- 通配符casadmin 可代理任何人 INSERT INTO surrogate_accounts VALUES (100, casuser, banderson); -- casuser 可代理 banderson INSERT INTO surrogate_accounts VALUES (200, casuser, surrogate2); INSERT INTO surrogate_accounts VALUES (300, casuser, surrogate3);要点username列存的是发起代理的管理员surrogateAccount列存的是被代理的目标账号表名与列名不是固定写死的——它们完全由你配置的 SQL 查询决定CAS 不关心物理表结构只关心查询返回的结果集当surrogateAccount的值为*接口中定义的WILDCARD_ACCOUNT时表示该管理员被授权冒充任意用户。四、两条核心 SQL 查询JDBC 模式除常规数据库配置外必须配置两条 SQL 查询一条判定资格eligibility一条取回可冒充账号列表。二者在 SurrogateJdbcAuthenticationProperties 中均被标注为RequiredProperty必填。4.1 资格查询surrogate-search-query默认值SELECT COUNT(*) FROM surrogate WHERE username?作用判定管理员 username 是否可以代理某人。执行后必须返回一个大于 0 的整数计数IntegerCAS 据此判断授权成立。配置项cas.authn.surrogate.jdbc.surrogate-search-querySELECT COUNT(*) FROM surrogate WHERE username?占位符参数顺序从 SurrogateJdbcAuthenticationService.canImpersonateInternal 可以看到该查询以surrogate.getId(), username的顺序绑定两个参数val count jdbcTemplate.queryForObject(surrogateSearchQuery, Integer.class, surrogate.getId(), username); return Objects.requireNonNull(count) 0;第 1 个?←被代理者surrogate user的 ID第 2 个?←管理员admin user的 username。因此若你的资格表同时校验管理员-目标账号二元关系而非仅校验管理员查询应写成测试中那样的形式cas.authn.surrogate.jdbc.surrogate-search-queryselect count(*) from surrogate_accounts where username? and surrogateAccount?4.2 账号列表查询surrogate-account-query默认值SELECT surrogate_user AS surrogateAccount FROM surrogate WHERE username?作用返回指定管理员username可以冒充的全部账号列表。CAS 会通过BeanPropertyRowMapper把结果集的每一行映射为SurrogateAccount对象并读取其surrogateAccount属性源码 L52-L57val results jdbcTemplate.query(surrogateAccountQuery, new BeanPropertyRowMapper(SurrogateAccount.class), username); return results.parallelStream().map(SurrogateAccount::getSurrogateAccount).collect(Collectors.toList());因此结果集必须包含一个可映射到surrogateAccount字段的列——要么列名就叫surrogateAccount或surrogate_accountHibernate 物理命名策略通常能兼容下划线命名要么像默认查询那样用别名显式声明AS surrogateAccount。例如cas.authn.surrogate.jdbc.surrogate-account-queryselect surrogateAccount from surrogate_accounts where username?或与测试一致的全列查询cas.authn.surrogate.jdbc.surrogate-account-queryselect * from surrogate_accounts where username?该查询只绑定一个参数管理员 username。4.3 查询支持 SpEL 表达式两条查询在真正执行前都会经过SpringExpressionLanguageValueResolver解析源码 L44-L54这意味着查询字符串中可以嵌入${...}形式的 Spring 表达式语言占位符便于从配置中心或环境变量动态注入表名、过滤条件等片段。五、完整配置参数清单所有配置均以cas.authn.surrogate.jdbc为前缀与源码中casProperties.getAuthn().getSurrogate().getJdbc()对应。5.1 模块专属参数配置项必填默认值说明cas.authn.surrogate.jdbc.surrogate-search-query✅SELECT COUNT(*) FROM surrogate WHERE username?资格判定 SQL返回大于 0 的整数即授权cas.authn.surrogate.jdbc.surrogate-account-query✅SELECT surrogate_user AS surrogateAccount FROM surrogate WHERE username?取回可冒充账号列表结果需含surrogateAccount列5.2 继承自 JPA 通用配置的数据库参数SurrogateJdbcAuthenticationProperties继承自 AbstractJpaProperties因此以下常规数据库设置同样适用均为cas.authn.surrogate.jdbc.*前缀配置项默认值说明driver-classorg.hsqldb.jdbcDriverJDBC 驱动类生产环境需替换为对应数据库驱动如com.mysql.cj.jdbc.Driver、org.postgresql.Driverurljdbc:hsqldb:mem:cas-hsql-database数据库连接 URL支持 SpEL 表达式解析usersa数据库用户需具备执行查询所需权限password空数据库密码dialectorg.hibernate.dialect.HSQLDialect数据库方言ddl-autoupdateHibernate 的 DDL 行为validate/update/create/create-drop/none生产环境建议validate或nonepool.*—连接池参数如pool.max-size、pool.min-size等见ConnectionPoolingPropertiesidle-timeoutPT10M连接池空闲超时ISO-8601 时长connection-timeoutPT30S获取连接最大等待时间leak-thresholdPT6S连接泄漏告警阈值autocommitfalse连接池默认自动提交行为测试用例中显式设置为true以立即执行 DDL/DMLread-onlyfalse连接是否以只读方式加入池health-query空对不支持 JDBC4isValid()的旧数据库执行的心跳 SQLdata-source-name—若指定则改为 JNDI 查找外部数据源properties.*—传递给 Hibernate / 连接提供方的额外键值对fail-fast-timeout1池初始化失败超时毫秒batch-size/fetch-size100Hibernate JDBC 批处理 / 抓取行数isolation-level-nameISOLATION_READ_COMMITTED事务隔离级别propagation-behavior-namePROPAGATION_REQUIRED事务传播行为一个完整的示例# 模块核心查询 cas.authn.surrogate.jdbc.surrogate-search-querySELECT COUNT(*) FROM surrogate WHERE username? AND surrogateAccount? cas.authn.surrogate.jdbc.surrogate-account-querySELECT surrogateAccount FROM surrogate WHERE username? # 数据库连接 cas.authn.surrogate.jdbc.driver-classcom.mysql.cj.jdbc.Driver cas.authn.surrogate.jdbc.urljdbc:mysql://localhost:3306/cas?useSSLfalseserverTimezoneUTC cas.authn.surrogate.jdbc.usercas cas.authn.surrogate.jdbc.passwordsecret # 连接池 cas.authn.surrogate.jdbc.pool.max-size10 cas.authn.surrogate.jdbc.pool.min-size2 cas.authn.surrogate.jdbc.connection-timeoutPT30S cas.authn.surrogate.jdbc.idle-timeoutPT10M六、底层实现与装配原理6.1 自动配置与数据源CasSurrogateJdbcAuthenticationAutoConfiguration 完成三件事通过JpaBeans.newDataSource(su.getJdbc())创建名为surrogateAuthenticationJdbcDataSource的独立数据源注意surrogate 存储使用独立数据源不与其他 JPA 模块共用以该数据源构造JdbcTemplate当surrogate-search-query非空时注册jdbcSurrogateAuthenticationServiceBeanBeanSupplier条件装配实现 SurrogateAuthenticationService 接口。Bean 均标注RefreshScope支持配置热刷新。6.2 判定链路canImpersonateSurrogateJdbcAuthenticationService继承自 BaseSurrogateAuthenticationService其canImpersonate是final模板方法判定顺序为serviceAuthorized (服务级代理策略是否允许) ( surrogate 与 principal 相同 —— 本人代理本人 || principal 属性命中核心配置的授权规则 || 命中通配符账户列表列表仅含 * || canImpersonateInternal(...) —— JDBC 资格查询 count 0 )其中服务级授权当请求关联了注册服务时会调用RegisteredServicePrincipalAccessStrategyEnforcer校验访问策略并检查WebBasedRegisteredService.getSurrogatePolicy().isEnabled()对应 Surrogate 访问策略见 Surrogate-Authentication-AccessStrategy.md属性级授权cas.authn.surrogate.core.principal-attribute-names与principal-attribute-values可配置基于管理员属性的授权规则详见 Surrogate-Core 配置JDBC 兜底只有前几项都不满足时才落到本文的 SQL 资格查询。6.3 通配符账户当getImpersonationAccounts返回的列表恰好只有一个元素且为*时接口的 isWildcardedAccount 判定该管理员为通配账户可代理任意用户。这也是测试中casadmin - *行存在的意义测试 L50。6.4 认证结果中的代理标记代理认证成功后CAS 会在认证上下文中写入三个属性collectSurrogateAttributes下游应用可据此识别这是一次冒充会话属性含义surrogateEnabled布尔值会话是否处于冒充状态surrogatePrincipal实际验证了凭证的管理员冒充者surrogateUser被冒充的代理用户七、验证方式测试用例即规格模块自带的 SurrogateJdbcAuthenticationServiceTests 继承自 BaseSurrogateAuthenticationServiceTests覆盖以下断言可作为你自建表结构时的行为基准verifyUserAllowedToProxycasuser的getImpersonationAccounts非空有banderson、surrogate2、surrogate3verifyUserNotAllowedToProxyunknown-user返回空列表verifyProxyingbanderson可被代理XXXX等无关账号不可verifyWildcardcasadmin因*记录可代理任何人。测试还演示了属性绑定风格surrogate-search-query、surrogate-account-query、auto-commit连字符小写形式与 5.1 节的配置项一一对应。八、与其它存储的组合CAS 允许多个账号存储同时启用例如 JDBC 与 LDAP、REST、JSON 等并存CAS 会从不同来源汇总可代理账号见 Surrogate-Authentication.md 的 Account Storage 小节。因此 JDBC 存储适合作为主存储再叠加简单存储或 REST 存储做补充各存储对应的指南分别为SimpleSurrogate-Authentication-Storage-Simple.mdJSONSurrogate-Authentication-Storage-JSON.mdLDAPSurrogate-Authentication-Storage-LDAP.mdRESTSurrogate-Authentication-Storage-REST.mdGroovySurrogate-Authentication-Storage-Groovy.md九、注意事项与最佳实践两条查询缺一不可二者均为RequiredProperty若surrogate-search-query为空自动配置将不会注册 JDBC 服务 Bean见 自动配置 L52。参数顺序不要写反资格查询的第 1 个占位符是被代理者 ID、第 2 个才是管理员用户名账号列表查询只有 1 个占位符管理员用户名。结果集列名要对齐账号列表查询必须能映射出surrogateAccount列拿不准就用AS surrogateAccount显式别名。资格查询返回类型CAS 以Integer接收计数查询应返回可被 JDBC 转成整数的聚合结果如COUNT(*)且以大于 0为授权判据。生产环境数据库设置将driver-class、url、user、password换成实际数据库ddl-auto建议设为validate或none避免 Hibernate 意外改表。通配符要慎用*记录赋予管理员代理任意账号的能力应只在受信任的管理员账号上配置。总结JDBC Surrogate 认证存储是 Apereo CAS 代理认证impersonation能力在关系型数据库上的落地实现通过cas-server-support-surrogate-authentication-jdbc模块 一张代理关系表 两条必填 SQL 查询即可让管理员以自己身份认证后切换到目标用户身份。理解资格查询与账号列表查询的占位符语义、surrogateAccount列映射规则和通配符机制是正确配置该存储的关键结合仓库中 自动配置、服务实现 与 测试用例你可以快速完成验证并按需扩展。赞分享后端认证鉴权单点登录【免费下载链接】casApereo CAS - Identity Single Sign On for all earthlings and beyond.项目地址https://gitcode.com/gh_mirrors/ca/cas点击查看免费下载相关推荐战略级文档迁移架构语雀Lake到Markdown的无损转换方案战略级文档迁移架构语雀Lake到Markdown的无损转换方案 在知识管理数字化转型的关键阶段企业面临着从封闭格式到开放标准的战略迁移挑战。语雀Lake格式后端认证鉴权单点登录3个惊人技巧让你的Android投屏工具scrcpy性能飙升300%3个惊人技巧让你的Android投屏工具scrcpy性能飙升300% 你是否曾经为Android设备投屏的卡顿和延迟而烦恼想要在电脑上流畅地控制手机却总是遇后端认证鉴权单点登录开源AI工程实战中小企业如何低成本部署智能应用开源AI工程实战中小企业如何低成本部署智能应用 面对AI技术浪潮许多中小企业和创业团队面临这样的困境看到大公司AI应用风生水起自己却不知从何入手。技术后端认证鉴权单点登录上一篇Go-Resty 项目推荐下一篇【亲测免费】 Centrifugo 开源项目推荐创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考