package com.aida.seller.common.aop; import com.aida.seller.common.annotation.InternalOnly; import com.aida.seller.common.constants.CommonConstants; import com.aida.seller.common.exception.BusinessException; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; /** * AOP 切面:校验 {@link InternalOnly} 标记的方法是否来自内部服务调用。 *

* 内部调用(Feign)会携带 {@link CommonConstants#INTERNAL_CALL_HEADER} Header, * 外部直接 HTTP 请求则不携带,视为非法访问。 */ @Slf4j @Aspect @Component @RequiredArgsConstructor public class InternalOnlyAspect { @Around("@annotation(com.aida.seller.common.annotation.InternalOnly)") public Object validateInternalCall(ProceedingJoinPoint joinPoint) throws Throwable { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (attributes == null) { throw new BusinessException("禁止外部直接访问此接口"); } HttpServletRequest request = attributes.getRequest(); String internalCall = request.getHeader(CommonConstants.INTERNAL_CALL_HEADER); if (!CommonConstants.INTERNAL_CALL_VALUE.equals(internalCall)) { log.warn("Unauthorized external access attempt to internal-only endpoint: {}", ((MethodSignature) joinPoint.getSignature()).getMethod().getName()); throw new BusinessException("禁止外部直接访问此接口"); } return joinPoint.proceed(); } }