Apereo CAS 认证事件 MongoDB 持久化指南:配置 `cas-server-support-events-mongo` 与事件仓库实现解析
2026/9/23 19:59:12 网站建设 项目流程
  • 后端
  • 认证鉴权
  • 单点登录

【免费下载链接】cas

Apereo CAS - Identity & Single Sign On for all earthlings and beyond.

项目地址:https://gitcode.com/gh_mirrors/ca/cas
点击查看免费下载

Apereo CAS 将认证过程中产生的各类事件(登录成功、登录失败、票据创建等)封装为统一的事件模型,并交由事件仓库(CasEventRepository)持久化。当事件仓库后端选用 MongoDB 时,认证事件会被写入 MongoDB 的指定集合中,供审计、监控、事件报表与风险分析使用。读完本文,你将掌握如何通过cas-server-support-events-mongo模块启用该能力、完整配置 MongoDB 连接与集合参数,并理解事件从产生、落库到被events管理端点查询的底层实现链路。

一、模块概述与启用方式

MongoDb 认证事件持久化由独立模块 cas-server-support-events-mongo 提供,其核心作用正如官方文档所述:将认证事件存储到 MongoDB NoSQL 数据库中("Stores authentication events into a MongoDb NoSQL database")。

启用方式是在 CAS 构建配置(Gradle 依赖管理)中加入该模块,坐标信息如下:

依赖模块:cas-server-support-events-mongo 组织:org.apereo.cas

加入依赖后,CAS 会自动装配 CasMongoDbEventsAutoConfiguration 中定义的三个核心 Bean:

Bean 名称类型职责
persistenceExceptionTranslationPostProcessorPersistenceExceptionTranslationPostProcessor将 MongoDB 数据访问异常转换为 Spring 持久化异常体系
mongoEventsTemplateMongoTemplate面向事件集合的 MongoDB 操作模板,负责建集合与读写
casEventRepositoryCasEventRepository事件仓库实现(MongoDbCasEventRepository),供 CAS 全局事件发布与消费使用

该自动配置类同时具备两个重要的装配前提:

  • 通过@ConditionalOnFeatureEnabled(feature = CasFeatureModule.FeatureCatalog.Events, module = "mongo")限定:只有 CAS 的Events 功能特性mongo 模块特性均被启用时才生效。该特性开关通常由cas.feature-flags相关配置或模块自动推导控制。
  • mongoEventsTemplatemongoEventRepositoryFilter均标注@ConditionalOnMissingBean,意味着开发者可以覆盖这些 Bean,自定义连接模板或事件过滤策略。
  • casEventRepository通过@Qualifier("mongoEventsTemplate")注入 MongoDB 模板,通过@Qualifier("mongoEventRepositoryFilter")注入事件过滤器。

1.1 从源码看事件入库链路

在 MongoDbCasEventRepository 中,事件写入与查询全部基于 Spring Data MongoDB 的MongoOperations

  • 写入saveInternal(CasEvent event)调用mongoTemplate.save(event.assignIdIfNecessary(), collectionName),先为事件分配 ID(若未设置则取System.currentTimeMillis(),见 CasEvent.assignIdIfNecessary),再写入指定集合。
  • 清空removeAll()使用mongoTemplate.remove(new Query(), CasEvent.class, collectionName)删除集合内全部事件。
  • 读取load()使用mongoTemplate.stream(...)以流式方式读取全部事件;load(ZonedDateTime)则在查询条件中追加creationTime >= dateTime.toInstant()的时间过滤。

二、配置参数详解(cas.events.mongo.*

模块的全部配置项统一挂在cas.events.mongo前缀之下,对应的配置模型是 MongoDbEventsProperties,它继承自SingleCollectionMongoDbPropertiesBaseMongoDbProperties。注意该属性类上的@RequiresModule(name = "cas-server-support-events-mongo")注解:未引入对应模块时,这些配置不会生效

2.1 集合相关配置

配置项默认值说明
cas.events.mongo.collectionMongoDbCasEventRepositoryMongoDB 中存放认证事件的集合名称。构造函数中通过setCollection("MongoDbCasEventRepository")预置,可覆盖
cas.events.mongo.drop-collectionfalse启动时是否先删除(drop)再重新创建集合。测试场景或需要清空历史数据时设为true

集合的创建发生在 CasMongoDbEventsAutoConfiguration#mongoEventsTemplate:MongoDbConnectionFactory.createCollection(mongoTemplate, mongo.getCollection(), mongo.isDropCollection())会在应用启动装配模板时按需创建集合。

2.2 连接相关配置

以下参数定义在 BaseMongoDbProperties 中,是 MongoDB 连接的基础设置:

配置项默认值说明
cas.events.mongo.client-uriMongoDB 连接 URI,形如mongodb://user:psw@ds135522.somewhere.com:35522/db。一旦指定将接管其他连接设置(优先级最高)
cas.events.mongo.hostlocalhostMongoDB 主机地址。多个地址用逗号分隔;若每个主机都自带端口,则端口以此为准
cas.events.mongo.port27017MongoDB 端口
cas.events.mongo.user-idMongoDB 认证用户名
cas.events.mongo.passwordMongoDB 认证密码
cas.events.mongo.database-nameMongoDB 数据库实例名(事件写入的目标数据库)
cas.events.mongo.authentication-database-name用于认证的数据库名称
cas.events.mongo.timeoutPT5S连接超时,ISO-8601 时长格式,如PT5S表示 5 秒
cas.events.mongo.write-concernACKNOWLEDGED写关注级别,描述 MongoDB 对写操作要求确认的程度
cas.events.mongo.read-concernAVAILABLE读关注级别,可选LOCALMAJORITYLINEARIZABLESNAPSHOTAVAILABLE
cas.events.mongo.read-preferencePRIMARY读偏好,可选PRIMARYSECONDARYSECONDARY_PREFERREDPRIMARY_PREFERREDNEAREST
cas.events.mongo.retry-writesfalse写操作因网络错误失败时是否自动重试
cas.events.mongo.ssl-enabledfalse连接是否启用 SSL
cas.events.mongo.replica-set副本集名称。副本集提供冗余与高可用,是生产部署的基础

此外,连接池相关参数由嵌套属性cas.events.mongo.pool.*提供(MongoDbConnectionPoolProperties),用于控制连接池大小、等待时间等。

2.3 完整配置示例(YAML)

cas: events: mongo: client-uri: mongodb://cas:secret@mongodb.example.org:27017/cas-events # 或使用分散参数: # host: localhost # port: 27017 # user-id: cas # password: secret # authentication-database-name: admin database-name: events collection: MongoDbCasEventRepository drop-collection: false timeout: PT5S write-concern: ACKNOWLEDGED read-concern: AVAILABLE read-preference: PRIMARY retry-writes: false ssl-enabled: false

以上配置与仓库测试用例 MongoDbCasEventRepositoryTests 中使用的参数一一对应,可作为最小可运行配置的参考:

cas.events.mongo.user-id=root cas.events.mongo.password=secret cas.events.mongo.host=localhost cas.events.mongo.port=27017 cas.events.mongo.authentication-database-name=admin cas.events.mongo.database-name=events cas.events.mongo.drop-collection=true

测试类还标注了@EnabledIfListeningOnPort(port = 27017),即只有在本地27017端口存在 MongoDB 实例时才会执行,这提示了该功能的运行前置条件:必须有一个可连接的 MongoDB 实例

三、事件数据模型:MongoDB 集合中的文档结构

写入 MongoDB 的事件文档对应 CasEvent 实体(位于api/cas-server-core-api-events模块),其字段结构如下:

JSON 字段类型说明
idlong事件唯一标识,写入时若小于等于 0 则以System.currentTimeMillis()填充
typeString事件类型,如CasAuthenticationTransactionSuccessfulEventCasAuthenticationTransactionFailureEvent等,非空
principalIdString与该事件关联的用户主体 ID,非空
creationTimeInstant事件创建时间,非空
propertiesMap<String, String>事件扩展属性键值对,单值最长 4000 字符

properties映射中常见的语义字段通过常量定义:

  • timestamp:事件时间戳(毫秒);
  • eventId:事件 ID;
  • clientip/serverip:客户端 / 服务端 IP;
  • agent:用户代理(浏览器/设备信息);
  • tenant:多租户场景下的租户标识;
  • geoLatitudegeoLongitudegeoAccuracygeoTimestampgeoAddress:地理位置相关(putGeoLocation统一写入);
  • deviceFingerprint:设备指纹。

这些扩展属性通过put(...)链式方法写入(空值会被移除),事件创建方(如认证成功/失败监听器)在发布事件前会填充 IP、Agent、地理位置等信息,MongoDB 仓库会将这些字段原样保存在文档的properties内嵌对象中。

3.1 查询字段与索引语义

MongoDbCasEventRepository 在查询时使用以下三个顶层字段构造Criteria

  • creationTime:时间范围过滤,gte(dateTime.toInstant())
  • type:事件类型精确匹配;
  • principalId:主体 ID 精确匹配。

仓库提供了 8 种查询组合(按类型、按主体、按时间及其任意组合),全部返回Stream<? extends CasEvent>流式结果。若需要在大数据量下保证查询性能,可以考虑在 MongoDB 中为creationTimetypeprincipalId建立合适的索引。

值得注意的是,基类 AbstractCasEventRepository 中带时间参数的查询默认采用内存过滤(load().filter(...)),而 MongoDB 实现则全部下推到数据库端执行(见MongoDbCasEventRepository中对load(ZonedDateTime)getEventsOfType(type, dateTime)等方法的覆写),因此在大数据量场景下 MongoDB 后端的查询效率更高。

四、保存流程:从事件发布到落库

CAS 的认证事件遵循"发布-订阅"模型。事件被发布后,casEventRepositorysave(...)方法被调用,其流程定义在 AbstractCasEventRepository#save 中:

  1. 调用eventRepositoryFilter.shouldSaveEvent(event)判断该事件是否需要持久化(默认过滤器为noOp(),即全部保存,见 CasMongoDbEventsAutoConfiguration#mongoEventRepositoryFilter);
  2. 通过则调用子类实现的saveInternal(event),即MongoDbCasEventRepository.saveInternal,将事件保存进 MongoDB 集合;
  3. 保存成功后,若配置了ApplicationEventPublisher,还会额外发布一个 Spring Boot Actuator 的AuditApplicationEvent(审计事件),其属性中包含CasEventRepository.PARAM_SOURCE = "CAS",从而与 CAS 的审计机制打通。

五、通过 Actuator 端点查询与管理事件

认证事件持久化到 MongoDB 后,可通过 CAS 的 Actuator 管理端点events进行查询与管理,该端点定义在 CasEventsReportEndpoint 中(端点 ID 为events,默认访问权限为Access.NONE,需显式开放):

  • GET /actuator/events?limit=1000:以 JSON 数组形式返回事件列表,按timestamp倒序排列,默认最多 1000 条;
  • GET /actuator/events/aggregate:以 NDJSON 流式返回聚合事件报表;
  • DELETE /actuator/events:清空事件仓库(对应MongoDbCasEventRepository.removeAll());
  • POST /actuator/events:导入单个事件(请求体为CasEventJSON)或上传 ZIP 压缩包(包内为多个.json事件文件)批量导入。

通过该端点可以直观验证 MongoDB 后端是否正常工作:写入几条认证事件后访问GET /actuator/events,应能看到来自 MongoDB 集合的完整事件数据。

六、快速验证与测试

仓库自带的集成测试 MongoDbCasEventRepositoryTests 继承自AbstractCasEventRepositoryTests,覆盖了事件保存、按类型/主体/时间查询、清空等全部仓库接口行为。若要在本地复现,需要:

  1. localhost:27017启动 MongoDB 实例(测试通过@EnabledIfListeningOnPort(port = 27017)检测端口);
  2. 准备测试库events及认证账号(测试用例使用root/secret,认证库admin);
  3. 运行该测试类,观察CasMongoDbEventsAutoConfiguration的装配与增删查改流程。

该测试同时验证了drop-collection=true的行为:每次启动都会先 drop 集合再重建,适用于开发调试;生产环境建议保持false,避免启动时误清历史事件数据。

七、小结与使用建议

  • 模块先行:使用前必须在构建中引入cas-server-support-events-mongo,否则cas.events.mongo.*配置不会生效;
  • 连接配置:推荐直接使用client-uri完成连接,其余参数作为精细化兜底;database-name决定事件写入哪个库,collection决定写入哪个集合(默认MongoDbCasEventRepository);
  • 生产建议:保持drop-collection: false;按typeprincipalIdcreationTime的查询模式为集合建立索引;结合eventsActuator 端点做日常巡检;
  • 生态定位:该模块是 CAS 事件仓库的 MongoDB 后端实现之一,与 JDBC、Redis、DynamoDb、Kafka 等后端实现并列(见 api/cas-server-core-api-configuration-model/src/main/java/org/apereo/cas/configuration/model/core/events 下的事件配置模型),选择 MongoDB 可获得 NoSQL 的灵活文档结构与流式读取能力,适合与现有 MongoDB 基础设施复用的部署场景。
  • 后端
  • 认证鉴权
  • 单点登录

【免费下载链接】cas

Apereo CAS - Identity & Single Sign On for all earthlings and beyond.

项目地址:https://gitcode.com/gh_mirrors/ca/cas
点击查看免费下载

相关推荐

上一篇:EvoDiff高级技巧:如何通过条件MSA生成新的蛋白质家族成员?
下一篇:Udeler代码注释规范:提升团队协作效率的文档实践

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询