- 后端
- 认证鉴权
- 单点登录
【免费下载链接】cas
Apereo CAS - Identity & Single Sign On for all earthlings and beyond.
本篇技术指南讲解 Apereo CAS 中基于 Hazelcast 分布式 Map 实现的认证节流(Authentication Throttling)方案:如何通过启用cas-server-support-throttle-hazelcast模块,让集群中所有 CAS 节点共享同一份"失败认证尝试"记录,从而在多节点部署下统一限制暴力破解与密码猜测行为。读完本文你将掌握该模块的依赖启用方式、cas.authn.throttle.hazelcast全系列配置项(含集群网络与 TLS 加密)、节流速率判定原理,以及从自动配置到后台清理任务的完整源码实现链路。
功能概述:用分布式 Map 记录节流尝试
CAS 的认证节流功能用于限制失败的登录尝试,以对抗密码猜测等滥用场景。官方文档 Configuring-Authentication-Throttling-Hazelcast.md 明确指出:
This feature uses a distributed Hazelcast map to record throttled authentication attempts.
即:该功能使用一张分布式 Hazelcast Map(默认名为ipMap)来记录被节流的认证尝试。与基于单机内存 Map 的方案不同,分布式 Map 让集群内的所有 CAS 节点读写同一份节流数据,任何节点记录的失败尝试都能被其他节点感知,因此特别适合部署在负载均衡之后的多节点 CAS 集群。
该组件同时依赖并需要 CAS 审计功能(见 Audits.md),因为节流事件的记录与审计(inspektr)体系共享同一套事件采集链路,失败尝试会作为审计动作(默认动作码AUTHENTICATION_FAILED)被登记。
启用模块
在配置 overlay(configuration overlay)中添加以下依赖即可启用该模块:
implementation "org.apereo.cas:cas-server-support-throttle-hazelcast"模块的 Maven 坐标为org.apereo.cas:cas-server-support-throttle-hazelcast。从源码结构看,该模块内部仅有三个类文件,职责高度聚焦:
CasHazelcastThrottlingAutoConfiguration:Spring Boot 自动配置入口(CasHazelcastThrottlingAutoConfiguration.java);HazelcastMapThrottledSubmissionsStore:基于 HazelcastIMap的节流记录存储实现(HazelcastMapThrottledSubmissionsStore.java);CasHazelcastThrottlingConfigurationTests:对应的单元测试(CasHazelcastThrottlingConfigurationTests.java)。
模块由特性开关(feature flag)控制:自动配置类标注了@ConditionalOnFeatureEnabled(feature = Throttling, module = "hazelcast"),只有认证节流特性启用且使用 hazelcast 存储时才会装配。
配置详解:cas.authn.throttle.hazelcast
该模块的全部配置统一挂在cas.authn.throttle.hazelcast前缀下,其顶层属性模型为HazelcastThrottleProperties(HazelcastThrottleProperties.java),它直接继承自BaseHazelcastProperties(BaseHazelcastProperties.java),内含两大块:cluster(集群配置)与core(Hazelcast 核心配置)。
Hazelcast 核心配置:cas.authn.throttle.hazelcast.core
对应属性类HazelcastCoreProperties(HazelcastCoreProperties.java):
| 属性 | 默认值 | 说明 |
|---|---|---|
cas.authn.throttle.hazelcast.core.license-key | 无 | Hazelcast 企业版许可证密钥。启用 WAN 复制、SSL 等企业特性时必需 |
cas.authn.throttle.hazelcast.core.enable-compression | false | 使用默认 Java 序列化时是否启用压缩 |
cas.authn.throttle.hazelcast.core.enable-management-center-scripting | true | 是否允许从 Management Center 执行脚本 |
cas.authn.throttle.hazelcast.core.enable-jet | true | 是否在 Hazelcast 实例上启用 Jet 服务(分布式批处理/流处理引擎,SQL 服务依赖它) |
Hazelcast 集群核心:cas.authn.throttle.hazelcast.cluster.core
对应属性类HazelcastCoreClusterProperties(HazelcastCoreClusterProperties.java),该组配置直接决定节流 Map 的数据分布、备份与驱逐行为:
| 属性 | 默认值 | 说明 |
|---|---|---|
cas.authn.throttle.hazelcast.cluster.core.instance-name | 无(必填) | 当前 Hazelcast 实例名称,支持 Spring 表达式语言(@ExpressionLanguageCapable)。测试用例中将其设为throttlehzstore |
cas.authn.throttle.hazelcast.cluster.core.async-fillup | true | 复制模式下新成员加入时是否异步填充:true不阻塞读写但数据渐进可见;false阻塞读写直到填充完成 |
cas.authn.throttle.hazelcast.cluster.core.replicated | false | 是否使用 Replicated Map(全量复制到所有成员,读快但内存占用高、更新量大时扩展性差) |
cas.authn.throttle.hazelcast.cluster.core.partition-member-group-type | 无 | 分区组策略:PER_MEMBER、HOST_AWARE、CUSTOM、ZONE_AWARE、SPI |
cas.authn.throttle.hazelcast.cluster.core.logging-type | slf4j | Hazelcast 日志适配:jdk、log4j、slf4j、none |
cas.authn.throttle.hazelcast.cluster.core.max-no-heartbeat-seconds | 300 | 节点心跳超时秒数,超过则认为节点死亡 |
cas.authn.throttle.hazelcast.cluster.core.map-merge-policy | PUT_IF_ABSENT | Map 合并策略:PUT_IF_ABSENT、HIGHER_HITS、DISCARD、PASS_THROUGH、EXPIRATION_TIME、LATEST_UPDATE、LATEST_ACCESS |
cas.authn.throttle.hazelcast.cluster.core.max-size | 85 | Map 最大条目数 |
cas.authn.throttle.hazelcast.cluster.core.max-size-policy | USED_HEAP_PERCENTAGE | 上限策略:FREE_HEAP_PERCENTAGE、FREE_HEAP_SIZE、FREE_NATIVE_MEMORY_PERCENTAGE、FREE_NATIVE_MEMORY_SIZE、PER_NODE、PER_PARTITION、USED_HEAP_PERCENTAGE、USED_HEAP_SIZE、USED_NATIVE_MEMORY_PERCENTAGE、USED_NATIVE_MEMORY_SIZE |
cas.authn.throttle.hazelcast.cluster.core.eviction-policy | LRU | 驱逐策略:LRU、LFU、NONE |
cas.authn.throttle.hazelcast.cluster.core.backup-count | 1 | 同步备份副本数,范围 0~6。设为 0 表示不备份(性能优先) |
cas.authn.throttle.hazelcast.cluster.core.async-backup-count | 0 | 异步备份副本数。异步备份不阻塞主操作 |
cas.authn.throttle.hazelcast.cluster.core.timeout | 5 | TCP/IP 配置与成员加入集群的连接超时(秒) |
cas.authn.throttle.hazelcast.cluster.core.cp-member-count | 0 | CP 子系统成员数(CP 子系统至少需要 3 个成员) |
Hazelcast 集群网络:cas.authn.throttle.hazelcast.cluster.network
对应属性类HazelcastNetworkClusterProperties(HazelcastNetworkClusterProperties.java):
| 属性 | 默认值 | 说明 |
|---|---|---|
cas.authn.throttle.hazelcast.cluster.network.tcpip-enabled | true | 是否启用 TCP/IP join 机制。新成员通过连接一个或多个已知成员来获知集群全貌 |
cas.authn.throttle.hazelcast.cluster.network.members | ["localhost"] | 集群已知成员列表,必须包含所有 CAS 节点(含当前节点),可用逗号分隔多个地址,如10.11.12.1,10.11.12.2 |
cas.authn.throttle.hazelcast.cluster.network.port | 5701 | Hazelcast 成员间通信端口 |
cas.authn.throttle.hazelcast.cluster.network.port-auto-increment | true | 是否允许端口自动递增。设为false可固定单端口(测试用例中即固定为5710) |
cas.authn.throttle.hazelcast.cluster.network.outbound-ports | 空 | 出站端口定义列表 |
cas.authn.throttle.hazelcast.cluster.network.local-address | 无 | 服务器 socket 绑定的本机地址覆盖值 |
cas.authn.throttle.hazelcast.cluster.network.public-address | 无 | 对外广播给其他成员与客户端的公共地址 |
cas.authn.throttle.hazelcast.cluster.network.network-interfaces | 无 | 允许使用的网卡接口(支持*与-范围通配,如10.3.10.*、10.3.10.4-18,逗号分隔) |
cas.authn.throttle.hazelcast.cluster.network.ipv4-enabled | true | 是否仅使用 IPv4 协议栈(部分平台如 AWS 不支持 IPv6,默认关闭 IPv6) |
Hazelcast 网络 TLS 加密:cas.authn.throttle.hazelcast.cluster.network.ssl
Hazelcast 支持通过 TLS(Transport Layer Security)协议,配合密钥库(key store)与信任库(trust store)在集群成员之间、以及成员与客户端之间建立端到端的 socket 级加密通信。对应属性类HazelcastNetworkSslProperties(HazelcastNetworkSslProperties.java)。
注意:Hazelcast SSL 属于企业版特性,启用该功能需要合法的 Hazelcast Enterprise License。
CAS 在启用 SSL 后会使用配置的密钥库自动初始化 SSL 上下文,并提供一个默认的 SSL context factory 实现来引导配置。主要属性如下:
| 属性 | 默认值 | 说明 |
|---|---|---|
cas.authn.throttle.hazelcast.cluster.network.ssl.protocol | TLS | TLS/SSL 协议算法,建议明确版本如TLSv1.2 |
cas.authn.throttle.hazelcast.cluster.network.ssl.keystore | 无 | 密钥库文件路径(使用双向认证时必需) |
cas.authn.throttle.hazelcast.cluster.network.ssl.keystore-password | 无 | 访问密钥库中密钥的口令 |
cas.authn.throttle.hazelcast.cluster.network.ssl.key-store-type | JKS | 密钥库类型,常用还有PKCS12 |
cas.authn.throttle.hazelcast.cluster.network.ssl.trust-store | 无 | 信任库文件路径(存放受信任证书集合) |
cas.authn.throttle.hazelcast.cluster.network.ssl.trust-store-type | JKS | 信任库类型 |
cas.authn.throttle.hazelcast.cluster.network.ssl.trust-store-password | 无 | 解锁信任库的口令 |
cas.authn.throttle.hazelcast.cluster.network.ssl.mutual-authentication | 无 | 双向认证:REQUIRED(强制客户端证书)或OPTIONAL(请求但不强制) |
cas.authn.throttle.hazelcast.cluster.network.ssl.cipher-suites | JVM 全部支持套件 | 允许使用的密码套件,逗号分隔 |
cas.authn.throttle.hazelcast.cluster.network.ssl.trust-manager-algorithm/key-manager-algorithm | 无 | 提供信任管理器 / 认证密钥的算法名称 |
Linux 熵源性能提示:在 Linux 下,JVM 默认使用/dev/random生成随机数。如果系统熵不足以跟上随机数的消耗速率,加解密可能阻塞长达数分钟。可通过设置系统属性-Djava.security.egd=file:/dev/./urandom缓解。需要注意:若熵确实不足,该选项不会阻塞,返回的随机值理论上可能更容易遭受密码学攻击,因此应权衡使用。
与节流核心配置联动
Hazelcast 存储只是节流记录的载体,节流的判定策略仍由cas.authn.throttle下的核心配置决定(属性模型见 ThrottleProperties.java):
失败判定:cas.authn.throttle.failure
对应ThrottleFailureProperties(ThrottleFailureProperties.java):
| 属性 | 默认值 | 说明 |
|---|---|---|
cas.authn.throttle.failure.code | AUTHENTICATION_FAILED | 记录到审计日志的失败动作码,标识认证失败事件 |
cas.authn.throttle.failure.threshold | -1 | 阈值内的失败登录次数 |
cas.authn.throttle.failure.range-seconds | -1 | 阈值对应的时间区间(秒) |
cas.authn.throttle.failure.throttle-window-seconds | 0 | 账号保持锁定/节流状态的秒数,超过该时间后释放。不设置则按失败阈值与速率计算 |
阈值速率(Threshold Rate):失败阈值速率按threshold / rangeSeconds计算。例如threshold=1、rangeSeconds=3时速率为0.333333。一次认证请求是否被节流,取决于该请求的提交速率(当前时间与上一次提交时间的差值的倒数)是否超过失败阈值速率——超过 1 次/3 秒的失败速率通常被视为自动化认证尝试,是制定节流策略的合理依据。无论策略如何,都需在安全与可用性之间权衡,过于严格可能阻止合法认证。
核心与调度:cas.authn.throttle.core / cas.authn.throttle.schedule
cas.authn.throttle.core(ThrottleCoreProperties.java):username-parameter(从请求中提取用户名的参数名)、header-name(从请求头提取值的头名)、app-code(审计日志中的应用标识,默认CAS)。cas.authn.throttle.schedule(SchedulingProperties.java):节流记录的后台清理任务。ThrottleProperties构造器中将其默认设为enabled=true、start-delay=PT10S、repeat-interval=PT30S。可选cron-expression与cron-time-zone;当使用 cron 表达式时必须将 start delay 与 repeat interval 置空。该调度周期直接决定了 Hazelcast 节流 Map 中记录的最大空闲存活时长(见下文源码分析)。
源码级实现原理
自动配置与ipMap的创建
CasHazelcastThrottlingAutoConfiguration.java 是模块装配的入口,其核心逻辑:
- 定义常量
MAP_KEY = "ipMap"作为分布式 Map 的名字; - 通过
@Qualifier("casTicketRegistryHazelcastInstance")注入 CAS 已有的 Hazelcast 实例(该实例同时服务于 ticket registry,体现复用同一集群的部署思路); - 将
cas.authn.throttle.schedule.repeat-interval解析为秒,作为 Map 条目的最大空闲时间(maxIdleSeconds); - 调用
HazelcastConfigurationFactory.buildMapConfig(hz, MAP_KEY, timeout)构建 Map 配置并注册到 HazelcastConfig; - 返回
HazelcastMapThrottledSubmissionsStore,以throttleSubmissionStore为 bean 名装配。
Map 配置的构建细节在 HazelcastConfigurationFactory.buildMapConfig 中可见:默认(非 replicated)情况下会生成标准MapConfig,应用maxSizePolicy、maxSize、evictionPolicy、backupCount、asyncBackupCount、mapMergePolicy等集群核心配置,设置maxIdleSeconds为节流调度周期,并使用二进制内存格式(InMemoryFormat.BINARY);若replicated=true则生成ReplicatedMapConfig并应用asyncFillup。
节流记录的存储与判定
HazelcastMapThrottledSubmissionsStore(HazelcastMapThrottledSubmissionsStore.java)继承自 BaseMappableThrottledSubmissionsStore.java,后者实现了接口 ThrottledSubmissionsStore.java 的put、get、contains、remove、clear、entries、exceedsThreshold、release等方法。其核心判定逻辑:
- 提交速率:
submissionRate = 1000.0 / (now - entry),即两次提交时间差的毫秒数换算为"次/秒"; - 超阈值判定:
exceedsThreshold比较当前提交速率与阈值速率,若前者大于后者则请求将被节流; - 释放逻辑:
release会逐条检查——已过期的直接删除;仍在expiration窗口内的保留;提交速率低于阈值速率的记录被释放删除。
Hazelcast 实现唯一重写的方法是removeIf:它将底层Map强转为IMap,使用hzMap.removeAll(Predicate)将条件判断下推至 Hazelcast 集群执行,而不是在本地迭代删除,从而保证多节点数据一致性。
单条节流记录的数据结构ThrottledSubmission(ThrottledSubmission.java)包含id、key(IP 或 IP+用户名)、value(UTC 提交时间)、username、clientIpAddress与expiration,并提供hasExpiredAlready()与isStillInExpirationWindow()两个过期判断方法。
请求拦截与后台清理
节流的触发位于认证请求拦截器链中:AbstractInMemoryThrottledSubmissionHandlerInterceptorAdapter(AbstractInMemoryThrottledSubmissionHandlerInterceptorAdapter.java)在认证失败时构造ThrottledSubmission并put进存储;在请求进入时先检查该 key 是否仍在节流窗口内、再调用exceedsThreshold判定是否需要拦截;release()则委托给存储的release(thresholdRate)。
后台清理由 InMemoryThrottledSubmissionCleaner.java 驱动,其@Scheduled注解的默认值为initialDelayString=PT10S、fixedDelayString=PT15S,可通过cas.authn.throttle.schedule.*覆盖;每次运行会遍历所有ThrottledSubmissionHandlerInterceptor并调用release(),从而周期性地从 Hazelcast Map 中淘汰过期与可释放的记录。
验证与测试
模块自带集成测试 CasHazelcastThrottlingConfigurationTests.java,它同时加载了 Hazelcast Ticket Registry 自动配置与本模块自动配置,并以真实属性启动:
cas.authn.throttle.hazelcast.cluster.network.port-auto-increment=false cas.authn.throttle.hazelcast.cluster.network.port=5710 cas.authn.throttle.hazelcast.cluster.core.instance-name=throttlehzstore测试流程完整覆盖存储生命周期:注入throttleSubmissionStorebean →put一条记录 →get断言可读取 → 断言entries().count()非零 →removeIf按条件删除 →remove按 key 删除 → 断言条目数为 0。该测试验证了ThrottledSubmissionsStore各操作在 Hazelcast 后端下的正确行为,可作为自定义扩展时的参考模板。
高可用与多节点部署注意事项
根据 Configuring-Authentication-Throttling-Failure.md 的说明,CAS 的节流组件适用于满足推荐 HA 架构的部署场景:
- 负载均衡启用**会话亲和(session affinity)**时,内存版组件可用:亲和性按源 IP 路由,来自固定位置的攻击者会绑定到同一 CAS 节点,节流记录因此完整;
- 而分布式攻击(请求被不确定地路由到不同节点)会让内存版组件记录分散,且攻击源本身多变,精确统计本就无意义——节流组件假定恒定源 IP 才能有效跟踪;
- 关键结论:登录节流组件不足以检测或阻止分布式密码暴力破解,无论使用内存还是 Hazelcast 存储都应配合其他防护手段。
选用 Hazelcast 存储的核心收益在于:当集群较大、会话亲和无法严格保证时,ipMap的分布式特性让所有节点共享同一份失败记录,节流判定不再依赖请求是否命中同一节点,从而在保证一致性的同时简化运维对路由策略的依赖。配置时请务必正确维护cluster.network.members列表(包含全部 CAS 节点)并确保cluster.network.port在各节点间可达;若启用 TLS 加密,还需为所有节点配置一致的信任库并准备 Hazelcast Enterprise License。
- 后端
- 认证鉴权
- 单点登录
【免费下载链接】cas
Apereo CAS - Identity & Single Sign On for all earthlings and beyond.
相关推荐
Apereo CAS 认证失败限流(Authentication Throttling)配置指南
Apereo CAS 认证失败限流(Authentication Throttling)配置指南 CAS 提供了一套内建的登录失败限流机制,用于限制连续失败的登
后端认证鉴权单点登录Apereo CAS OIDC 认证的 MongoDb JWKS 存储实战指南
Apereo CAS OIDC 认证的 MongoDb JWKS 存储实战指南 本篇技术指南围绕 Apereo CAS 的 OpenID Connect 认证能
后端认证鉴权单点登录Apereo CAS 认证事件 Redis 存储:Redis Authentication Events 配置与实现详解
Apereo CAS 认证事件 Redis 存储:Redis Authentication Events 配置与实现详解 在 Apereo CAS 中,认证事件
后端认证鉴权单点登录
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考