Spring Boot如何从AuthorizationFailureEvent中获取Request URL
问题解答
异常出现的原因
Spring Security触发的AuthorizationFailureEvent的事件源类型,由授权校验的触发场景决定:
- 当授权校验在Web过滤器链阶段执行(即你在
HttpSecurity配置中定义的URL路径权限规则),此时事件源为FilterInvocation类型,可以强转后获取请求URL - 当授权校验在方法AOP代理阶段执行(即你在Controller/Service方法上添加了
@PreAuthorize、@PreFilter等方法级安全注解),此时授权校验是在Spring AOP的方法调用流程中触发的,事件源为ReflectiveMethodInvocation类型,和过滤器链无关,强转为FilterInvocation自然会抛出ClassCastException。
你当前的场景就是触发了方法级的授权校验,因此拿到的事件源不符合预期。
正确获取请求URL的方案
最通用的方案是直接从Spring Web的请求上下文持有者RequestContextHolder中获取当前请求对象,无需依赖事件源的类型,适配所有Web请求触发的授权事件:
修改后的代码示例
private void onAuthorizationFailureEvent(AuthorizationFailureEvent event) { Map<String, Object> data = new HashMap<>(); data.put("type", event.getAccessDeniedException().getClass().getName()); data.put("message", event.getAccessDeniedException().getMessage()); // 从请求上下文获取请求URL,替代原来的从事件源获取的逻辑 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (attributes != null) { HttpServletRequest request = attributes.getRequest(); data.put("requestUrl", request.getRequestURL().toString()); } if (event.getAuthentication().getDetails() != null) { data.put("details", event.getAuthentication().getDetails()); } publish(new AuditEvent(event.getAuthentication().getName(), AUTHORIZATION_FAILURE, data)); }
注意事项
- 如果你的应用存在非Web请求触发的方法调用(比如定时任务、内部RPC调用),
RequestContextHolder.getRequestAttributes()会返回null,上述代码中的空判断可以避免空指针异常。 - 如果你不需要用到方法级安全校验,也可以将所有权限规则都统一配置到
HttpSecurity的URL路径规则中,此时所有的授权失败事件源都为FilterInvocation,你原来的代码也可以正常运行,但该方案适配性不如第一种方案。
内容的提问来源于stack exchange,提问作者wxkevin
相关产品推荐
相关产品推荐

