自定义 AOP 弹簧启动注释,带功能区客户端阻止 API 调用,返回"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

通过从poster调用api,请求被正确地发送到第二个微服务,我确信返回是";真";。

之后,请求在输入createUpdateRequirement方法之前停止,并返回"1"作为邮递员主体响应。没有提供排序错误。

我的猜测是,这个问题存在于自定义注释中,因为当我删除注释时,api调用可以完美地工作,但我无法理解这个问题,因为对我来说,它似乎都设置正确了。

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

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

此外,around是本机AspectJ语法中的保留关键字。即使它可能在注释驱动的语法中工作,您也应该将您的建议方法重命名为aroundAdviceinterceptPreHasAuthority之类的其他方法。

请阅读AspectJ或Spring AOP教程,尤其是Spring手册的AOP章节。

最新更新