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

Spring Security:仅在授权访问接口时触发登录成功操作

解决Spring Security中仅在权限验证通过后执行操作的问题

你遇到的问题本质是认证(Authentication)和授权(Authorization)是Spring Security中两个完全独立的阶段:AuthenticationSuccessEvent只负责监听「用户登录成功」这个认证节点事件,不管后续用户有没有访问目标接口的权限,只要用户名密码校验通过就会触发。而你需要的是在**授权校验成功(用户拥有对应接口的访问权限)**时执行指定操作,所以得从授权阶段的钩子入手。

下面结合你的代码场景,给你几个可行的实现方案:


方案一:监听Spring Security的AuthorizationSuccessEvent(推荐,Spring Security 5.6+)

从Spring Security 5.6版本开始,框架原生提供了AuthorizationSuccessEvent,这个事件会在所有授权校验通过后触发,完美匹配你的需求。

实现代码:

@Component
public class AuthorizationSuccessEventListener implements ApplicationListener<AuthorizationSuccessEvent> {

    private static final Logger log = LoggerFactory.getLogger(AuthorizationSuccessEventListener.class);

    @Autowired
    private HttpServletRequest request;

    @Override
    public void onApplicationEvent(AuthorizationSuccessEvent event) {
        // 获取当前登录用户信息
        Authentication authentication = event.getAuthentication();
        String username = ((UserAccountDetails) authentication.getPrincipal()).getUsername();
        
        // 获取当前请求的接口和HTTP方法信息
        String requestUri = request.getRequestURI();
        String httpMethod = request.getMethod();
        
        log.info("用户 {} 成功通过权限校验,访问接口:{} {}", username, httpMethod, requestUri);
        // 在这里执行你需要的记录/自定义操作逻辑
    }
}

注意:

如果你的Spring Security版本低于5.6,建议升级到对应稳定版本,享受这个原生事件带来的便捷性。


方案二:自定义AOP切面拦截带@PreAuthorize的方法

如果你无法升级框架版本,可以用Spring AOP来切面所有标记了@PreAuthorize的方法——因为@PreAuthorize是在方法执行前做权限校验,只要方法能正常执行,就说明权限校验已经通过。

实现代码:

  1. 切面类实现:
@Component
@Aspect
public class PreAuthorizeSuccessAspect {

    private static final Logger log = LoggerFactory.getLogger(PreAuthorizeSuccessAspect.class);

    @Autowired
    private HttpServletRequest request;

    // 拦截所有带有@PreAuthorize注解的方法,在方法执行后触发逻辑
    @AfterReturning("@annotation(org.springframework.security.access.prepost.PreAuthorize)")
    public void afterPreAuthorizeSuccess(JoinPoint joinPoint) {
        // 获取当前登录用户
        UserAccountDetails user = (UserAccountDetails) AuthorizationUtils.getUserDetails();
        if (user == null) {
            return;
        }
        String username = user.getUsername();
        
        // 获取方法和接口信息
        String methodName = joinPoint.getSignature().getName();
        String requestUri = request.getRequestURI();
        String httpMethod = request.getMethod();
        
        log.info("用户 {} 成功通过权限校验,执行方法:{},访问接口:{} {}", username, methodName, httpMethod, requestUri);
        // 执行你的记录/自定义操作逻辑
    }
}
  1. 开启AOP支持:
    在你的Spring配置类上添加@EnableAspectJAutoProxy注解,确保AOP切面生效。

方案三:扩展MethodSecurityInterceptor(底层定制)

如果你需要更底层的权限控制扩展,可以继承Spring Security处理方法级权限的核心类MethodSecurityInterceptor,在授权成功后插入自定义逻辑。

实现代码:

  1. 自定义Interceptor:
@Component
public class CustomMethodSecurityInterceptor extends MethodSecurityInterceptor {

    private static final Logger log = LoggerFactory.getLogger(CustomMethodSecurityInterceptor.class);

    @Autowired
    private HttpServletRequest request;

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        // 先执行Spring Security原生的授权逻辑
        Object result = super.invoke(invocation);
        
        // 能走到这里说明权限校验已通过
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        String username = ((UserAccountDetails) authentication.getPrincipal()).getUsername();
        
        String requestUri = request.getRequestURI();
        String httpMethod = request.getMethod();
        
        log.info("用户 {} 成功通过权限校验,访问接口:{} {}", username, httpMethod, requestUri);
        // 执行你的记录/自定义操作逻辑
        
        return result;
    }
}
  1. 配置Spring Security使用自定义Interceptor:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {

    @Autowired
    private CustomMethodSecurityInterceptor customMethodSecurityInterceptor;

    @Override
    protected MethodSecurityInterceptor methodSecurityInterceptor() {
        return customMethodSecurityInterceptor;
    }
}

额外提示:

  • 方案一的AuthorizationSuccessEvent会覆盖所有授权场景(包括URL级权限校验、方法级权限校验),如果只想针对@PreAuthorize的方法,可以在监听器里判断事件的AuthorizationDecision来源。
  • 所有方案中获取用户信息时建议做判空处理,避免极端情况下的空指针问题(不过你的接口都加了权限校验,正常场景下用户都是已登录状态)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 19:57:57