我有一个多模块 Spring Boot 应用程序,每个模块都依赖于审计服务(该服务只有一个名为audit() 的方法,它实际上所做的就是使用 WebClient 调用另一个应用程序,发送有关当前用户的一些数据).
目前,它被注入到每个模块的服务类中,并且仅发送一些硬编码数据(因为身份验证尚未准备好),但现在我需要提取用户信息(从 OAuth JWT 声明中)并实际传递该信息与令牌一起向审计应用程序发出经过身份验证的请求。
模块主要服务之一的伪代码
class ActualService {
AuditService auditSvc
ActualRepository actualRepo
public void updateSomething(RequestDTO request, JWT authenticatedUser) {
....doSomething()
auditSvc.audit(someHardcodedValues)
}
}
实现这一目标的正确方法是什么?我正在考虑将审计服务注入到每个模块的控制器中,并在调用实际的主服务方法之后和将响应返回给客户端之前调用审计方法(并将整个 JWT 传递给它)。
像这样
class ActualController {
AuditService auditSvc
ActualService actualService
@PutMapping
public ResponseEntity<String> updateSomething(RequestDTO request, JWT authenticatedUser) {
actualService.updateSomething(request, authenticatedUser)
auditSvc.audit(authenticatedUser)
return ResponseEntity.OK
}
}
但我不知道这是否是一个好方法。欢迎任何想法,谢谢
将审计服务注入每个模块的控制器并在主服务方法之后调用审计方法是一种合理的方法,特别是如果您想确保以模块化方式对每个请求进行一致的审计。不过,有一些注意事项需要牢记:
代码重复:将审计服务注入多个控制器可能会导致代码重复。如果每个模块都有相似的审计代码,则将审计逻辑封装在公共实用程序或方面可能会有益,以避免在每个控制器中重复相同的代码。
跨领域关注点:审计通常被认为是跨领域关注点,这意味着它跨越应用程序的多个层。您可能希望利用 AOP(面向方面编程)以更加模块化和侵入性较小的方式处理这个问题。 AOP 允许您定义可应用于不同类的各种方法的方面。
这是使用 AOP 的修改方法:
@Aspect
@Component
public class AuditingAspect {
private final AuditService auditService;
@Autowired
public AuditingAspect(AuditService auditService) {
this.auditService = auditService;
}
@AfterReturning("execution(* com.example..controller.*.*(..)) && args(request, authenticatedUser)")
public void audit(JoinPoint joinPoint, RequestDTO request, JWT authenticatedUser) {
// Extract relevant information from authenticatedUser and call audit service
auditService.audit(authenticatedUser);
}
}
在
AuditingAspect
中,我们使用 Spring AOP 来拦截接受 RequestDTO
和 JWT
作为参数的控制器类中的方法执行。该方法成功返回后,调用切面的audit
方法进行审计。
在 Spring Boot 应用程序的配置中,确保启用 Spring AOP:
@SpringBootApplication
@EnableAspectJAutoProxy
public class YourApplication {
// ...
}
通过启用
@EnableAspectJAutoProxy
,您允许 Spring 识别和处理方面。
通过这种方法,您可以将审核逻辑与控制器和服务分开,减少代码重复并确保跨模块一致地应用审核。
请调整方面配置和切入点以匹配您的特定包结构和要求。此外,请记住根据应用程序的需要处理异常并自定义审核逻辑。