Grails 3.2.5 REST Security插件双重认证问题求助
这问题我之前帮朋友排查过类似的,双重认证触发大概率是Spring Security过滤器链被重复执行了,结合你给的日志和Grails 3.2.5的环境,咱们一步步来定位解决:
1. 排查过滤器链的重复匹配配置
Grails Spring Security REST插件的过滤器链配置很容易踩坑——如果你的chainMap里有重叠的路径匹配规则,比如/**和/api/**同时存在,就会导致同一个请求被两次匹配过滤链,触发两次认证逻辑。
打开你的application.yml,找到Spring Security的chainMap配置,改成这样:
grails: plugin: springsecurity: filterChain: chainMap: # 先匹配需要令牌验证的API路径 - pattern: '/api/**' filters: 'JOINED_FILTERS,-anonymousAuthenticationFilter,-exceptionTranslationFilter,-authenticationProcessingFilter' # 再匹配其他路径,避免重复覆盖 - pattern: '/**' filters: 'JOINED_FILTERS,-restTokenValidationFilter'
重点是给/**的过滤器链去掉restTokenValidationFilter,避免非API请求重复触发令牌验证,同时确保API路径只被匹配一次。
2. 检查HiddenHttpMethodFilter的干扰
从你的日志里看到HiddenHttpMethodFilter$HttpMethodRequestWrapper,这个过滤器在Grails里默认是启用的,它会把POST请求里的_method参数转换成对应HTTP方法,但有时候会导致请求被重新包装转发,触发第二次过滤链。
你可以先临时禁用它试试,在application.yml里加:
grails: web: hiddenmethod: enabled: false
如果禁用后双重认证消失了,那就是这个过滤器的锅,你可以调整它的执行顺序,让它在Spring Security过滤器之后运行,而不是之前。
3. 给自定义监听器加触发条件
你的AuthenticationSuccessListener现在是只要有AuthenticationSuccessEvent就触发,但令牌验证每次请求都会刷新安全上下文,也会触发这个事件。你可以修改监听器,只处理首次交互式认证或者判断认证是否是新生成的:
class CustomAuthenticationSuccessListener implements ApplicationListener<AuthenticationSuccessEvent> { @Override void onApplicationEvent(AuthenticationSuccessEvent event) { // 只处理真正的登录成功事件,而非每次令牌验证的上下文刷新 if (event instanceof InteractiveAuthenticationSuccessEvent) { // 你的业务逻辑 log.debug("处理首次登录成功事件: ${event.authentication.name}") } // 或者判断认证是否是刚创建的(比如不是从缓存/令牌中加载的) // if (!event.authentication.details?.class?.simpleName == "WebAuthenticationDetails") { // // 处理逻辑 // } } }
4. 验证RestTokenValidationFilter的生效范围
确保令牌验证过滤器只对需要的路径生效,在application.yml里配置:
grails: plugin: springsecurity: rest: token: validation: active: true # 只对API路径启用令牌验证 endpointUrl: '/api/**'
这样就不会让非API请求触发令牌验证,减少不必要的事件触发。
从你提供的日志片段来看,第一次过滤链已经完成了令牌验证,但没有进入GrailsDispatcherServlet,反而重新执行了过滤链,这大概率是某个过滤器转发了请求导致的,先试试上面的前两个方案,应该能解决问题。
内容的提问来源于stack exchange,提问作者Jay

