【问题标题】:How to enforce Aspect implementation is loaded when its corresponding annotation is used?使用相应的注解时如何强制加载 Aspect 实现?
【发布时间】:2022-11-11 01:41:08
【问题描述】:

我创建了一个注释,用于验证某些安全方面是否正确。

例如,@RequireClientCertificate,带有一个 Aspect 实现RequireClientCertificateAspect,用于验证是否确实将正确的 HTTP 标头传递到 Spring REST 控制器。

如果实际加载了RequireClientCertificateAspect,即如果在@ComponentScan() 的某处提到了它的包,这完全可以正常工作。

但是,如果有人忘记将这个包添加到@ComponentScan,或者切面被移动到另一个包,或者有人(不小心)从@ComponentScan 中删除了包,则切面bean 没有加载,切面完全没有应用。

我在一个公共库中有这个注释,由多个微服务共享,因此其中一个微服务很容易意外出错。在这种情况下,不会检查客户端证书。

问题:如果使用了@RequireClientCertificate 注释,我如何强制执行它对应的Aspect 实现也被加载?


简化使用示例:

@Controller
@RequestMapping(value = "/v1.0", produces = MediaType.APPLICATION_JSON_VALUE)
@RequireClientCertificate
public class SomeApiController {

    @ResponseBody
    @PostMapping("/get-token/")
    public ResponseEntity<Token> getToken() {
        return ResponseEntity.ok(...get token...);
    }
}

方面的简化版本:

@Aspect
@Component
public class RequireClientCertificateAspect {
    @Around("execution(* (@RequireClientCertificate *).*(..))")
    public Object requireClientCertificateAspectImplementation(ProceedingJoinPoint joinPoint) throws Throwable {
        ... verify request header ...
        try {
            return joinPoint.proceed();
        finally {
            ... some other things I need to check ...
        }
    }
}

我尝试过/考虑过的事情:

我可以通过向接口添加带有初始化程序的静态字段来检测注释的“使用情况”。例如:

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RestFactoryGatewaySecurityContext {
    static public final boolean dummy = SomeClass.checkAspectIsLoaded();
}

但是,这样的初始化程序很早就被调用了,而且我认为 Spring DI 在那个阶段还没有“启动并运行”得足够远,以至于我什至可以可靠地确定是否加载了方面 bean。

另一种选择是使用@Autowired 在主应用程序类上显式注入RequireClientCertificateAspect bean。如果不知何故 bean 不在组件扫描中,这将阻止 Spring 实例化应用程序。

所以这确实有效,但需要有人明确添加这个“虚拟”自动连线,除了有点“丑陋”之外,它本身很容易忘记。

【问题讨论】:

  • 我建议创建一些集成测试并检查该方面是否有效。
  • 当然。但是这些测试在公共库中。即使我会在微服务中为它编写一个额外的测试,我如何确保测试的 ComponentScan 等于主程序的呢?当然,有人可能再次忘记在新的微服务中编写这样的测试。
  • [更新]对不起,我误读了您的评论,并阅读了单元测试。是的,还需要集成测试,但我宁愿保持安全,以防有人忘记编写它们(假设它“正常工作”,因为注释肯定在那里......)。

标签: java spring aop


【解决方案1】:

如果您使用 spring boot,您可以创建自己的启动器。

创建文件META-INF/spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.MyCustomConfiguration

然后只需将您想要的任何验证添加到您的配置中

@Configuration
public class MyCustomConfiguration{
}

您可以将@Autowired 您的RequireClientCertificateAspect 放入其中,如果未定义将导致错误。

您可以使用@PostConstruct 创建方法并进行任何您想要的验证。

如果您创建自定义启动器,您可以在那里初始化您的 bean。

有关它的更多信息,您可以阅读here

【讨论】:

    猜你喜欢
    • 2021-04-13
    • 1970-01-01
    • 1970-01-01
    • 2021-05-18
    • 2012-05-21
    • 1970-01-01
    • 1970-01-01
    • 2016-03-04
    • 2011-04-27
    相关资源
    最近更新 更多