我创建了一个注解,用于验证某些安全方面是否正确。
例如,@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();
}
然而,这样的初始化器在很早的时候就被调用了,我认为SpringDI在那个阶段还没有“启动并运行”到我甚至可以可靠地确定方面bean是否被加载的程度。
另一个选择是使用@Autowired在主应用类上显式地注入RequireClientCertificateAspect
bean。如果该bean不在组件扫描中,这将阻止Spring示例化该应用。
所以这确实有效,但需要有人明确地添加这个“虚拟”autowire,它本身很容易忘记,除了有点“丑陋”。
1条答案
按热度按时间bt1cpqcv1#
如果你使用 Spring Boot ,你可以创建自己的启动器。
创建文件
META-INF/spring.factories
:然后,只需将所需的任何验证添加到配置中即可
您可以将您的
@Autowired
RequireClientCertificateAspect
插入其中,如果未定义,则会导致错误。您可以使用
@PostConstruct
创建方法并执行任何所需验证。如果你已经创建了自定义启动器,你可以在那里初始化你的bewns。
更多关于它,你可以阅读here