自定义 AOP spring 带功能区客户端阻止 api 调用的引导注释 return“1”

Custom AOP spring boot annotation with ribbon client blocking api call with return "1"

我对 ribbon/eureka 的体验真的很差,如果这是一个愚蠢的问题,请原谅我:

我有两个不同的微服务都连接到发现服务器,第一个使用自定义注释调用第二个,该注释使用 rest 模板发送请求。 自定义注释名称是 PreHasAuthority

控制器:

    @PreHasAuthority(value="[0].getProject()+'.requirements.update'")
    @PostMapping(CREATE_UPDATE_REQUIREMENT)
    public ResponseEntity<?> createUpdateRequirement(@Valid @RequestBody RequirementDTO requirementDTO
, HttpServletRequest request, HttpServletResponse response) {
        
        return requirementService.createUpdateRequirement(requirementDTO, request, response);
    }

注释界面:


import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PreHasAuthority {

    String value();
    
}

注解实现:

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;

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.beans.factory.annotation.Autowired;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.stereotype.Component;

import netcomgroup.eu.service.AuthenticationService;

@Aspect
@Component
public class PreHasAuthorityServiceAspect {

    @Autowired
    private AuthenticationService authenticationService;
    
    @Around(value = "@annotation(PreHasAuthority)")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        PreHasAuthority preHasAuthority = method.getAnnotation(PreHasAuthority.class);
        
        Object[] args = joinPoint.getArgs();
        String permission = preHasAuthority.value();
        ExpressionParser elParser = new SpelExpressionParser();
        Expression expression = elParser.parseExpression(permission);
        String per = (String) expression.getValue(args);
        
        String token =null;
        for(Object o : args) {
            if(o instanceof HttpServletRequest) {
                HttpServletRequest request = (HttpServletRequest)o;
                token=request.getHeader("X-Auth");
                break;
            }
        }
        
        if(token==null) {
            throw new IllegalArgumentException("Token not found");
        }
        
        boolean hasPerm = authenticationService.checkPermission(per,token);
        
        if(!hasPerm) 
            throw new Exception("Not Authorized");
    }
}

我的功能区配置

import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RoundRobinRule;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;

public class RibbonConfiguration {

    @Autowired
    IClientConfig config;

    @Bean
    public IRule ribbonRule(IClientConfig config) {
        return new RoundRobinRule();
    }
}

应用程序属性中的 Eureka 配置

#Eureka config
eureka.client.serviceUrl.defaultZone= http://${registry.host:localhost}:${registry.port:8761}/eureka/
eureka.client.healthcheck.enabled= true
eureka.instance.leaseRenewalIntervalInSeconds= 10
eureka.instance.leaseExpirationDurationInSeconds= 10

通过从邮递员调用 api 请求正确发送到第二个微服务,我确定 return 是“真”。

之后,请求在进入 createUpdateRequirement 方法和 returns '1' 作为邮递员正文响应之前停止。没有提供排序错误。

我的猜测是问题出在自定义注释中,因为当我删除注释时,api 调用工作正常,但我无法理解问题,因为它对我来说似乎都设置正确。

您的 @Around 建议从未调用 joinPoint.proceed()。因此,截获的目标方法将永远不会被执行。

第二个问题是您的建议方法 returns void,即它永远不会匹配任何返回另一种类型的方法,例如 ResponseEntity<?> createUpdateRequirement(..) 方法。

此外,around 是原生 AspectJ 语法中的保留关键字。即使它可能适用于 annotation-driven 语法,您也应该将建议方法重命名为 aroundAdviceinterceptPreHasAuthority 之类的其他名称。

请务必阅读 AspectJ 或 Spring AOP 教程,尤其是 Spring manual's AOP chapter