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

Grails 4.0.9集成spring security core grails plugin 4.0.3如何记录登录成败尝试

Grails 4.0.9 + Spring Security Core 4.0.3 登录事件捕获实现方案

你当前使用的版本完全支持登录成功、失败行为的捕获需求,无需重写核心认证逻辑、自定义登录接口,通过插件基于Spring Security原生提供的两类扩展点即可实现,两种方案可根据业务场景灵活选择。

方案一:Spring认证事件监听(零侵入,推荐优先使用)

Spring Security本身内置了完整的认证事件发布机制,该版本的Grails插件会自动在用户认证流程的对应节点发布事件,仅需注册对应的事件监听器即可捕获行为,不需要修改任何默认登录配置。

  • 可监听的核心事件类型:
    • 登录成功类:InteractiveAuthenticationSuccessEvent(表单等交互式登录触发)、AuthenticationSuccessEvent(所有认证场景,包括记住我、程序级认证触发),可根据需要捕获的范围选择监听
    • 登录失败类:AuthenticationFailureEvent(所有认证失败场景的父类,可直接监听捕获所有失败类型,包括账号密码错误、账号锁定、账号禁用、密码过期等),也可按需单独监听AuthenticationFailureBadCredentialsEvent等细分失败事件

将以下类放在src/main/groovy目录下,标注@Component即可被Grails自动扫描加载:

import org.springframework.security.authentication.event.AuthenticationFailureEvent
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent
import org.springframework.stereotype.Component
import org.springframework.web.context.request.RequestContextHolder

import javax.servlet.http.HttpServletRequest

@Component
class LoginAuditListener {

    // 捕获交互式登录成功事件
    @EventListener
    void handleLoginSuccess(InteractiveAuthenticationSuccessEvent event) {
        String username = event.authentication.name
        HttpServletRequest request = RequestContextHolder.requestAttributes.request
        // 适配反向代理场景的IP取值
        String clientIp = request.getHeader("X-Forwarded-For") ?: request.remoteAddr
        // 在此处实现业务逻辑:记录审计日志、更新用户最后登录时间、触发登录成功通知等
        log.info("用户[$username] 从IP[$clientIp]登录成功")
    }

    // 捕获所有类型的登录失败事件
    @EventListener
    void handleLoginFailure(AuthenticationFailureEvent event) {
        // 失败场景下需兼容不同取值位置获取提交的用户名
        String username = event.authentication?.name ?: event.authentication.principal
        HttpServletRequest request = RequestContextHolder.requestAttributes.request
        String clientIp = request.getHeader("X-Forwarded-For") ?: request.remoteAddr
        // 在此处实现业务逻辑:记录失败次数、触发账号锁定阈值校验、留存攻击痕迹等
        log.info("用户[$username] 从IP[$clientIp]登录失败,原因:${event.exception.message}")
    }
}

方案二:自定义认证成功/失败Handler(适合需修改登录流程的场景)

如果需要在捕获登录行为的同时,修改默认的登录成功跳转、失败跳转逻辑,可以选择自定义Handler,通过覆盖插件默认配置生效。

  1. 自定义成功Handler,继承插件默认的成功跳转逻辑类:
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import org.springframework.security.core.Authentication

class CustomLoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
    @Override
    void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
        // 前置实现登录成功的捕获逻辑
        String username = authentication.name
        log.info("用户[$username]登录成功")
        // 调用父类逻辑保留默认的跳转规则
        super.onAuthenticationSuccess(request, response, authentication)
    }
}
  1. 自定义失败Handler,继承插件默认的失败跳转逻辑类:
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import org.springframework.security.core.AuthenticationException

class CustomLoginFailureHandler extends SimpleUrlAuthenticationFailureHandler {
    @Override
    void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) {
        // 前置实现登录失败的捕获逻辑
        String submittedUsername = request.getParameter("username")
        log.info("用户[$submittedUsername]登录失败,原因:${exception.message}")
        // 调用父类逻辑保留默认的失败跳转规则
        super.onAuthenticationFailure(request, response, exception)
    }
}
  1. 在grails-app/conf/application.groovy的Spring Security配置块中替换默认的Handler:
grails.plugin.springsecurity.successHandler.authenticationSuccessHandler = new CustomLoginSuccessHandler()
grails.plugin.springsecurity.failureHandler.authenticationFailureHandler = new CustomLoginFailureHandler()

实现注意事项

  • 两种方案无冲突,可按需组合使用:事件监听方式耦合度低,适合做独立的审计、统计类需求;自定义Handler方式灵活度高,适合需要联动调整登录跳转、请求响应的场景
  • 从事件/请求中获取用户名、IP信息时需做好空值判断,兼容反向代理场景的请求头取值逻辑,避免获取到代理服务器IP、空用户名的问题
  • 无需额外引入第三方依赖,上述类全部基于Spring Security、Grails内置能力实现,和你当前使用的插件版本完全兼容

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.28 22:15:07