Apereo CAS 自定义服务访问策略执行器(Custom Service Access Strategy Enforcer)实现指南
后端认证鉴权单点登录身份认证【免费下载链接】casApereo CAS - Identity Single Sign On for all earthlings and beyond.项目地址https://gitcode.com/gh_mirrors/ca/cas点击查看免费下载在 Apereo CAS 中服务的访问授权Service Access Strategy决定了一个已注册的应用服务能否参与 CAS 认证/SSO 流程。本篇指南聚焦于 CAS 预留的自定义扩展点——RegisteredServiceAccessStrategyEnforcer通过实现该接口并注册为 Spring Bean你可以完全接管或补充 CAS 的服务授权判定逻辑把自定义的授权规则如对接内部风控系统、调用业务侧决策 API 等无缝嵌入 CAS 运行时。读完本文你将掌握自定义执行器的接口契约、注册方式、调用链原理以及如何与 CAS 自带的 Groovy 执行器协同工作。一、核心概念什么是 RegisteredServiceAccessStrategyEnforcer在 CAS 中服务访问授权由两类组件协作完成访问策略Access Strategy与具体服务定义RegisteredService绑定声明式地描述该服务在什么条件下允许访问例如必须携带哪些属性、启用/禁用、是否允许 SSO 等典型实现如DefaultRegisteredServiceAccessStrategy。访问策略执行器Access Strategy Enforcer在认证与票据签发等关键节点被调用的执行入口负责在运行时把访问策略真正执行起来并产出可审计的结果。本指南的主角是后者。RegisteredServiceAccessStrategyEnforcer是 CAS 从7.0.0起提供的扩展接口其定义位于 RegisteredServiceAccessStrategyEnforcer.javaFunctionalInterface public interface RegisteredServiceAccessStrategyEnforcer extends AuditableExecution { }接口本身非常精简它是一个标注了FunctionalInterface的空接口继承自AuditableExecution。真正需要实现的只有一个方法——来自AuditableExecution的AuditableExecutionResult execute(AuditableContext context) throws Throwable;AuditableExecution接口定义于 AuditableExecution.java其 javadoc 明确指出它是CAS 服务器及其各模块在诸多审计点上的审计轨迹执行抽象实现者通常还会使用 Inspektr 审计库的Audit注解捕获审计数据。二、注册自定义执行器原文档核心步骤原文档给出的注册方式非常直接编写一个AutoConfiguration配置类声明一个返回RegisteredServiceAccessStrategyEnforcer的BeanCAS 会在运行时自动拾取并用于授权执行。完整示例package org.apereo.cas; AutoConfiguration EnableConfigurationProperties(CasConfigurationProperties.class) public class MyConfiguration { Bean RefreshScope(proxyMode ScopedProxyMode.DEFAULT) public RegisteredServiceAccessStrategyEnforcer myEnforcer() { return new MyRegisteredServiceAccessStrategyEnforcer(); } }其中需要你自行实现MyRegisteredServiceAccessStrategyEnforcer例如public class MyRegisteredServiceAccessStrategyEnforcer implements RegisteredServiceAccessStrategyEnforcer { Override public AuditableExecutionResult execute(final AuditableContext context) throws Throwable { // 读取上下文中的服务、认证、票据等信息执行自定义授权判定 final AuditableExecutionResult result AuditableExecutionResult.builder() .registeredService(context.getRegisteredService().orElse(null)) .service(context.getService().orElse(null)) .build(); if (/* 你的授权规则不通过 */) { result.setException(UnauthorizedServiceException.denied(Custom rule denied access)); } return result; } }注意Bean方法上的RefreshScope(proxyMode ScopedProxyMode.DEFAULT)它使该 Bean 具备热刷新能力当外部属性变化触发 CAS 上下文刷新时执行器实例可被自动重建。让 CAS 识别你的 AutoConfigurationAutoConfiguration类需要被 Spring Boot 的自动装配机制发现。参照 Configuration-Management-Extensions.md 的说明在 CAS Overlay 的src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中追加一行org.apereo.cas.MyConfiguration用 Conditional 覆盖 CAS 自带执行器CAS 自身也在 CasCoreServicesConfiguration.java 中注册了执行器相关 Bean且大多带有ConditionalOnMissingBean(name ...)守卫ConditionalOnMissingBean(name AuditableExecution.AUDITABLE_EXECUTION_REGISTERED_SERVICE_ACCESS) Bean RefreshScope(proxyMode ScopedProxyMode.DEFAULT) public AuditableExecution registeredServiceAccessStrategyEnforcer(...) { return new RegisteredServiceAccessStrategyAuditableEnforcer(applicationContext, principalAccessStrategyEnforcer); }AuditableExecution.AUDITABLE_EXECUTION_REGISTERED_SERVICE_ACCESS的值为registeredServiceAccessStrategyEnforcer。这意味着只要你自定义的 Bean 使用相同的 Bean 名称即可整体替换 CAS 默认的执行器。若你只想追加一层自定义判定而不替换默认实现则直接按上文声明一个新命名的 Bean 即可——下文会说明两者在调用链上的差异。三、执行链原理自定义执行器如何被调用CAS 默认执行器是RegisteredServiceAccessStrategyAuditableEnforcer见 RegisteredServiceAccessStrategyAuditableEnforcer.java。它的execute方法按优先级依次尝试多种判定路径Override Audit(action AuditableActions.SERVICE_ACCESS_ENFORCEMENT, actionResolverName AuditActionResolvers.SERVICE_ACCESS_ENFORCEMENT_ACTION_RESOLVER, resourceResolverName AuditResourceResolvers.SERVICE_ACCESS_ENFORCEMENT_RESOURCE_RESOLVER) public AuditableExecutionResult execute(final AuditableContext context) { return byExternalAccessStrategyEnforcers(context) .or(() - byServiceTicketAndAuthnResultAndRegisteredService(context)) .or(() - byServiceAndRegisteredServiceAndTicketGrantingTicket(context)) .or(() - byServiceAndRegisteredServiceAndPrincipal(context)) .or(() - byServiceAndRegisteredServiceAndAuthentication(context)) .or(() - byServiceAndRegisteredService(context)) .or(() - byRegisteredService(context)) .orElseGet(() - { /* ...默认拒绝... */ }); }关键的一步是byExternalAccessStrategyEnforcers(context)——它从 Spring 上下文中取出所有RegisteredServiceAccessStrategyEnforcer类型的 Bean按顺序执行并收集第一个执行失败的结果protected OptionalAuditableExecutionResult byExternalAccessStrategyEnforcers(final AuditableContext context) { return accessStrategyEnforcers .orderedStream() .filter(BeanSupplier::isNotProxy) .map(Unchecked.function(enforcer - enforcer.execute(context))) .filter(Objects::nonNull) .filter(AuditableExecutionResult::isExecutionFailure) .findFirst(); }由此可以得出两个重要结论追加型注册推荐你新增的执行器 Bean 会被byExternalAccessStrategyEnforcers一并收集执行。只要你的执行器返回带异常的结果isExecutionFailure() true授权即被拒绝若返回无异常的结果CAS 会继续走内置的默认判定路径。替换型注册若用同名 Bean 覆盖registeredServiceAccessStrategyEnforcer你的执行器将完全替代上述整套判定逻辑此时你需要自行处理各类上下文分支。而执行器的调用入口位于核心认证服务 DefaultCentralAuthenticationService.javaprotected void enforceRegisteredServiceAccess(final AuditableContext audit) throws Throwable { val accessResult configurationContext.getRegisteredServiceAccessStrategyEnforcer().execute(audit); accessResult.throwExceptionIfNeeded(); }也就是说在 CAS 认证 / 授权 / 验证的关键流程中一旦上下文被构造为AuditableContext携带service、registeredService、principal等就会触发执行器若结果携带异常则通过throwExceptionIfNeeded()抛出如UnauthorizedServiceException最终阻断请求。上下文与结果对象AuditableContextAuditableContext.java执行器收到的输入通过SuperBuilder构建可包含service、registeredService、principal、authentication、serviceTicket、authenticationResult、ticketGrantingTicket、httpRequest、httpResponse以及扩展属性properties。这些字段均通过Optional暴露你的自定义执行器应做好空值判断。AuditableExecutionResultAuditableExecutionResult.java执行器返回的结果通过setException(...)标记失败isExecutionFailure()判断是否失败throwExceptionIfNeeded()抛出异常。此外还可通过addProperty(...)向结果追加自定义属性供审计消费。四、源码佐证CAS 自带的 Groovy 执行器实现CAS 仓库中提供了一个开箱即用的RegisteredServiceAccessStrategyEnforcer实现——GroovyRegisteredServiceAccessStrategyEnforcerGroovyRegisteredServiceAccessStrategyEnforcer.java。它可以作为你编写自定义执行器的绝佳参照public class GroovyRegisteredServiceAccessStrategyEnforcer implements RegisteredServiceAccessStrategyEnforcer, DisposableBean { private final ExecutableCompiledScript script; Override public Nullable AuditableExecutionResult execute(final AuditableContext context) throws Throwable { val args new Object[]{context, LOGGER}; return script.execute(args, AuditableExecutionResult.class, true); } Override public void destroy() { script.close(); } }它在 CasCoreServicesConfiguration.java 中通过条件 Bean 注册配置项为cas.access-strategy.groovy.locationConditionalOnMissingBean(name groovyRegisteredServiceAccessStrategyEnforcer) Bean RefreshScope(proxyMode ScopedProxyMode.DEFAULT) ConditionalOnMissingGraalVMNativeImage public RegisteredServiceAccessStrategyEnforcer groovyRegisteredServiceAccessStrategyEnforcer(...) { return BeanSupplier.of(RegisteredServiceAccessStrategyEnforcer.class) .when(BeanCondition.on(cas.access-strategy.groovy.location).exists() .given(applicationContext.getEnvironment())) .supply(() - { val location casProperties.getAccessStrategy().getGroovy().getLocation(); val scriptFactory ExecutableCompiledScriptFactory.getExecutableCompiledScriptFactory(); return new GroovyRegisteredServiceAccessStrategyEnforcer(scriptFactory.fromResource(location)); }) .otherwiseProxy() .get(); }对应配置属性模型定义于 AccessStrategyProperties.java即cas.access-strategy.groovy.location指向一个 Groovy 脚本资源。该脚本与自定义执行器走的是同一条调用链脚本接收AuditableContext与LOGGER两个参数返回AuditableExecutionResult。仓库测试资源 ServiceAccessStrategy.groovy 给出了脚本的完整写法import org.apereo.cas.audit.* import org.apereo.cas.services.* def run(Object[] args) { def context args[0] as AuditableContext def logger args[1] logger.info(Checking access for ${context.registeredService}) if (context.service.isPresent()) { def service context.service.get() logger.info(Service request is ${service.id}) if (service.id.startsWith(https://)) { def result AuditableExecutionResult.builder().build() result.setException(UnauthorizedServiceException.denied(Service Unauthorized)) logger.error(Service ${service.id} is unauthorized by Groovy script) return result } } return AuditableExecutionResult.builder().build() }对应的测试类 GroovyRegisteredServiceAccessStrategyEnforcerTests.java 验证了执行器返回失败结果的完整链路测试以cas.access-strategy.groovy.locationclasspath:ServiceAccessStrategy.groovy启动上下文注入registeredServiceAccessStrategyEnforcer与groovyRegisteredServiceAccessStrategyEnforcer构造包含registeredService、service、authentication的AuditableContext后执行并断言results.isExecutionFailure()为真。这同时印证了自定义执行器只需在execute中返回带异常的结果即可实现授权拒绝。五、与 Groovy 全局策略的关系与选型建议需要区分两个层面的 Groovy 扩展全局执行器层即上文GroovyRegisteredServiceAccessStrategyEnforcer配置项cas.access-strategy.groovy.location对所有服务的授权执行生效属于执行器层面的策略。服务级策略层即GroovyRegisteredServiceAccessStrategy见 Service-Access-Strategy-Groovy.md挂在单个服务定义 JSON 的accessStrategy字段上属于访问策略层面的声明。两者叠加使用时判定顺序为先执行全局执行器含你的自定义执行器再落入默认执行器的内置策略判定。若你的场景需要全站统一、强定制的授权逻辑如调用外部决策引擎自定义RegisteredServiceAccessStrategyEnforcer是正确选择若只需为个别服务声明规则优先使用服务级策略或 Groovy 脚本策略。六、完整落地步骤小结实现接口在 CAS Overlay 工程中创建MyRegisteredServiceAccessStrategyEnforcer implements RegisteredServiceAccessStrategyEnforcer在execute(AuditableContext)中编写授权逻辑返回AuditableExecutionResult拒绝时setException(UnauthorizedServiceException.denied(...))。声明 Bean编写AutoConfigurationEnableConfigurationProperties(CasConfigurationProperties.class)配置类以BeanRefreshScope(proxyMode ScopedProxyMode.DEFAULT)暴露执行器若需替换默认执行器Bean 名称须为registeredServiceAccessStrategyEnforcer。注册装配将配置类全限定名写入META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports。验证参照 GroovyRegisteredServiceAccessStrategyEnforcerTests.java 的写法编写集成测试构造AuditableContext并断言执行结果通过 CAS 审计日志SERVICE_ACCESS_ENFORCEMENT确认执行器被调用。上线观察利用RefreshScope的能力在属性变更触发上下文刷新时热更新执行器配置避免频繁重启。至此你已经掌握了 CAS 自定义服务访问策略执行器的完整实现路径从接口契约、Bean 注册、调用链原理到测试验证均可在当前仓库中找到对应的源码与测试佐证可据此把任意业务授权规则安全、可控地接入 CAS 的认证授权流程。赞分享后端认证鉴权单点登录身份认证【免费下载链接】casApereo CAS - Identity Single Sign On for all earthlings and beyond.项目地址https://gitcode.com/gh_mirrors/ca/cas点击查看免费下载相关推荐Thorium 浏览器下载安装完整指南Thorium 浏览器下载安装完整指南 如果你习惯了 Chrome却嫌页面响应慢、新界面不合手Thorium 值得装来试试。它是一款基于 Chromium后端认证鉴权单点登录身份认证CAS 服务访问策略链Service Access Strategy Chaining配置与原理解析CAS 服务访问策略链Service Access Strategy Chaining配置与原理解析 本篇指南围绕 Apereo CAS 注册服务Regi后端认证鉴权单点登录身份认证Apereo CAS 注册服务自定义属性Service Custom Properties配置指南Apereo CAS 注册服务自定义属性Service Custom Properties配置指南 导读 本文介绍 Apereo CAS 中注册服务Reg后端认证鉴权单点登录身份认证上一篇openeuler/distributed-beget最佳实践10个提升参数管理效率的技巧下一篇Piko 登录令牌导入/导出补丁Import/Export login token完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

OpCore-Simplify 快速上手:从硬件报告到可用 OpenCore EFI 的完整指南

OpCore-Simplify 快速上手:从硬件报告到可用 OpenCore EFI 的完整指南

OpCore-Simplify 快速上手:从硬件报告到可用 OpenCore EFI 的完整指南 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify 装黑苹果最磨人的两…

2026/10/16 2:31:53 阅读更多 →
以撒的结合:忏悔 REPENTOGON 枚举详解:SuplexState 与 Suplex! 道具状态机

以撒的结合:忏悔 REPENTOGON 枚举详解:SuplexState 与 Suplex! 道具状态机

游戏开发插件系统 【免费下载链接】REPENTOGON Script extender for The Binding of Isaac: Repentance 项目地址: https://gitcode.com/gh_mirrors/re/REPENTOGON 点击查看 免费下载 导读 SuplexState 是 REPENTOGON(《The Binding of Isaac: Repenta…

2026/10/16 2:30:53 阅读更多 →
LAMMPS fix python/invoke:在分子动力学模拟过程中周期性调用 Python 回调函数

LAMMPS fix python/invoke:在分子动力学模拟过程中周期性调用 Python 回调函数

科研科学计算高性能计算 【免费下载链接】lammps Public development project of the LAMMPS MD software package 项目地址: https://gitcode.com/gh_mirrors/la/lammps 点击查看 免费下载 fix python/invoke 是 LAMMPS PYTHON 包提供的一个特殊 fix,…

2026/10/16 2:30:53 阅读更多 →

最新新闻

微信小程序圆环组件开发:Canvas 2D与CSS方案选型及性能优化实战

微信小程序圆环组件开发:Canvas 2D与CSS方案选型及性能优化实战

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

2026/10/16 3:13:02 阅读更多 →
interface 的底层原理

interface 的底层原理

深入浅出 Go 语言:Interface 的底层实现原理在 Go 语言中,接口(interface)是实现多态和解耦的核心机制。与其他面向对象语言不同,Go 采用的是“隐式实现”(Duck Typing,鸭子类型)——…

2026/10/16 3:13:02 阅读更多 →
【C++入门】编译链接模型 - 08 静态库为什么像一包目标文件

【C++入门】编译链接模型 - 08 静态库为什么像一包目标文件

博主介绍:程序喵大人 35 - 资深C/C/Rust/Android/iOS客户端开发10年大厂工作经验嵌入式/人工智能/自动驾驶/音视频/游戏开发入门级选手《C20高级编程》《C23高级编程》等多本书籍著译者更多原创精品文章,首发gzh,见文末👇&#x…

2026/10/16 3:13:02 阅读更多 →
重复测量数据全攻略:2026 一篇讲透论文重复测量实验设计,把变量控制与记录规范讲清

重复测量数据全攻略:2026 一篇讲透论文重复测量实验设计,把变量控制与记录规范讲清

同一批被试在四个时间点各测一次,交到导师手里却被追问「你的实验设计写在哪」。重复测量方差分析、线性混合模型这些名称不难写,难的是交代清楚每次观测为何落在这个时点、谁在中途退出、缺失值依据什么规则处置。下文从自变量控制、测量间隔、批次安排…

2026/10/16 3:13:02 阅读更多 →
信贷风控用户画像实战:从标签体系到贷前贷中贷后策略落地

信贷风控用户画像实战:从标签体系到贷前贷中贷后策略落地

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

2026/10/16 3:13:02 阅读更多 →
Java字符串转数字的正确方法

Java字符串转数字的正确方法

java中把字符串转成 的方法更新时间为二零二三年七月七日零九点四十分零三秒, 作者是。在Java环境里头, 大家可以利用某个类里面的那个叫作静态的方法, 把一段写着数字的字符串变成对应那种类型的数, 这篇文章会配上一些具体的代码例子, 来把这个事情从字符串弄成具体数值的过程…

2026/10/16 3:12:01 阅读更多 →

日新闻

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

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

2026/10/16 0:00:05 阅读更多 →
信号与系统频域分析作业解题指南

信号与系统频域分析作业解题指南

1. 作业背景与核心要求解析信号与系统作为电子信息类专业的核心基础课,其作业设计往往直接关联课程的核心知识框架。2026年春季第六次作业的布置,通常对应着课程进展到频域分析的关键阶段。根据常规教学进度推测,本次作业可能涉及以下核心内容…

2026/10/16 0:00:05 阅读更多 →
Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

1. 从一个"四不像"的练手项目说起如果你已经看完了Django的官方教程前几章,跟着敲完了投票应用,大概会有一种"我好像会了,又好像什么都不会"的割裂感。教程里每个知识点都是拆开的——这一章讲模型,下一章讲视…

2026/10/16 0:00:05 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 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/15 0:14:36 阅读更多 →
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/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练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/15 9:49:14 阅读更多 →