You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Keycloak 26如何永久存储无效登录尝试记录?

问题分析

你当前使用Keycloak 26.3.0的暴力检测功能时,失败登录次数默认存储在Infinispan缓存中,缓存过期后计数器会自动重置;而永久锁定是直接写入数据库用户实体(user_entity表的enabled字段设为false),因此两者行为不一致。

内置方案:调整缓存有效期(非持久化)

Keycloak没有内置直接将失败次数持久化到数据库的配置,但可以通过调整缓存过期规则避免计数器过早重置:

  • 找到Keycloak的standalone.xml(或domain.xml)配置文件,定位到infinispan子系统中名为bruteForce的缓存容器。
  • 修改其缓存的expiration配置,将max-idle设为极大值,或直接禁用过期:
<cache-container name="bruteForce" default-cache="authFailures">
  <local-cache name="authFailures">
    <expiration max-idle="-1"/> <!-- -1表示禁用缓存过期 -->
  </local-cache>
</cache-container>

注意:这种方法只是延长缓存有效期,并非真正持久化到数据库,若Keycloak重启或缓存集群出现异常,计数器仍可能丢失。

持久化到数据库的方案:自定义BruteForceProtector SPI

若要将失败次数永久存储到数据库,必须自定义SPI实现:

  1. 编写自定义BruteForceProtector类
    继承DefaultBruteForceProtector,重写处理失败次数的核心方法(incrementFailureCount、resetFailureCount、getFailureCount),将操作直接对接数据库。可使用Keycloak提供的JpaTransactionManager或JDBC完成数据库操作,核心逻辑示例:
@Override
public void incrementFailureCount(RealmModel realm, UserModel user) {
    // 从数据库读取当前失败次数
    int currentCount = getFailureCountFromDB(realm.getId(), user.getId());
    // 更新数据库中失败次数
    updateFailureCountToDB(realm.getId(), user.getId(), currentCount + 1);
    // 可选:保留缓存同步以提升性能
    super.incrementFailureCount(realm, user);
}
  1. 注册SPI
    在项目的META-INF/services/org.keycloak.services.managers.BruteForceProtector文件中,添加自定义类的全限定名。
  2. 打包部署
    将自定义扩展打包为JAR,放入Keycloak的providers目录,重启Keycloak后在管理控制台启用该SPI。
  3. 扩展数据库表(可选)
    若Keycloak默认表无存储失败次数的字段,可新增user_login_failures表,关联user_entity表的id字段,存储用户ID、领域ID、失败次数、最后失败时间等信息。
额外注意事项
  • 自定义SPI时需处理事务一致性,避免缓存与数据库数据不一致。
  • Direct Grant模式下,默认DefaultBruteForceProtector已支持失败次数统计,重写对应方法即可覆盖该流程。
  • 测试时需验证:失败次数成功写入数据库、缓存过期后计数器不丢失、永久锁定逻辑不受影响。

内容的提问来源于stack exchange,提问作者Ipay Test

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.11 14:03:11