在控制器上 spring PreAuthorize 之后使用 AspectJ 进行审计

Audit using AspectJ after spring PreAuthorize on controller

我正在尝试审核 Spring 应用程序中成功和失败的 OAuth2 身份验证尝试的日志。我正在使用 Spring 的 @PreAuthorize 注释,如下所示。

@RequestMapping(value = "/{id}", method = RequestMethod.GET)
@PreAuthorize("#oauth2.hasScope('read')")
public Person getById(@PathVariable String id) {
    return service.getById(id);
}

认证授权正常。为了尝试进行审计​​日志记录,我尝试使用 AspectJ 进行一些 AOP,如下所示。

@Component
@Aspect
public class AuditLogger {


    @After("@annotation(org.springframework.security.access.prepost.PreAuthorize)")
    public void afterAuth(JoinPoint joinPoint) throws Throwable {

        // do audit logging

    }

}

但是,只有在身份验证和授权都成功时才会发生这种情况。这些是场景:

我最好的猜测是 Spring 在身份验证或授权失败时会做一些不同的事情,但我不确定如何解决它。有什么建议吗?

在一个文件中找不到执行此操作的好方法,所以我最终使用一个文件来处理失败的身份验证请求(使用事件),另一个文件处理成功的身份验证请求(使用方面)。我用一个自定义的 MyAnnotation 注释了我的所有控制器,其中包含一些关于控制器的信息。这可能不是最好的解决方案,但希望它能帮助别人。

失败:

@Component
public class FailedAuthRequestAuditor {

    private ApplicationContext context;
    private AuditEventLogger logger;

    @Autowired
    public FailedAuthRequestAuditor(
        ApplicationContext context,
        AuditEventLogger logger
    ) {
        this.context = context;
        this.logger = logger;
    }

    @EventListener
    public void onBadCredentialsEvent(AuthenticationFailureBadCredentialsEvent event) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        Method destinationMethod = this.getDestination(request);

        if (destinationMethod != null) {
            // do logging here
        }
    }

    @EventListener
    public void onAuthorizationFailureEvent(AuthorizationFailureEvent event) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        Method destinationMethod = this.getDestination(request);

        if (destinationMethod != null) {
            // do logging here
        }
    }


    private Method getDestination(HttpServletRequest request) {
        for (HandlerMapping handlerMapping : context.getBeansOfType(HandlerMapping.class).values()) {
            HandlerExecutionChain handlerExecutionChain = null;
            try {
                handlerExecutionChain = handlerMapping.getHandler(request);
            } catch (Exception e) {
                // do nothing
            }

            if (handlerExecutionChain != null && handlerExecutionChain.getHandler() instanceof HandlerMethod) {
                return ((HandlerMethod) handlerExecutionChain.getHandler()).getMethod();
            }
        }

        return null;
    }

}

成功:

@Aspect
@Component
public class SuccessfulAuthRequestAuditor {

    private AuditEventLogger auditEventLogger;
    private AuditEventOutcomeMapper mapper;

    @Autowired
    public SuccessfulAuthRequestAuditor(AuditEventLogger auditEventLogger, AuditEventOutcomeMapper mapper) {
        this.auditEventLogger = auditEventLogger;
        this.mapper = mapper;
    }

    @AfterReturning(pointcut = "execution(@com.company.MyAnnotation * *(..)) && @annotation(myAnnotation) && args(request,..)", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result, MyAnnotation myAnnotation, HttpServletRequest request) {
        // do logging
    }

    @AfterThrowing(pointcut = "execution(@com.company.MyAnnotation * *(..)) && @annotation(myAnnotation) && args(request,..)", throwing = "exception")
    public void afterThrowing(JoinPoint joinPoint, Throwable exception, MyAnnotation myAnnotation, HttpServletRequest request) {
        // do logging
    }
}