代码记录
首先要在maven中配置相关的aop配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
编写自己的Annotation
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DomainCheck {
/**
* 类或接口是否配置了domain信息
* @return
*/
String[] domains() default {};
/**
* 默认是类或者接口需是 domains 配置的 domain 才能访问
* @return
*/
boolean isPositive() default true;
}
编写Aspect aop 代码
@Slf4j
@Aspect
@Component
public class DomainCheckAop {
// 方法级别的annotation 切点
@Order(10)
@Pointcut("execution(* com.huawei.analysis.controller..*.*(..)) && @annotation(domainCheck)")
public void domainMethodCheckAop(DomainCheck domainCheck) {
}
@Before(value = "domainMethodCheckAop(domainCheck)", argNames = "joinPoint,domainCheck")
public void domainMethodCheckBefore(JoinPoint joinPoint, DomainCheck domainCheck) throws DomainCheckException {
log.info("domainMethodCheckBefore");
domainCheck(joinPoint, domainCheck);
}
// 类级别的annotation 切点
@Order(9)
@Pointcut("within(com.huawei.analysis.controller..*) && @within(domainCheck)")
public void domainClassCheckAop(DomainCheck domainCheck) {
}
@Before(value = "domainClassCheckAop(domainCheck)", argNames = "joinPoint,domainCheck")
public void domainClassCheckBefore(JoinPoint joinPoint, DomainCheck domainCheck) throws DomainCheckException {
log.info("domainClassCheckBefore");
// 需要判断接口方法是否配置了 annotation
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
if (methodSignature.getMethod().isAnnotationPresent(DomainCheck.class)) {
// 类上配置了 annotation 且方法上也配置了,优先使用方法上的配置
log.info("类上配置了 DomainCheck 注解,方法上也使用了,即使用方法上的配置信息");
DomainCheck annotation = methodSignature.getMethod().getAnnotation(DomainCheck.class);
domainCheck(joinPoint, annotation);
} else {
domainCheck(joinPoint, domainCheck);
}
}
private void domainCheck(JoinPoint joinPoint, DomainCheck domainCheck) throws DomainCheckException {
String[] domains = domainCheck.domains();
boolean positive = domainCheck.isPositive();
if (domains.length > 0) {
Signature signature = joinPoint.getSignature();
String declaringTypeName = signature.getDeclaringTypeName();
log.info("declaringTypeName : {}", declaringTypeName);
MethodSignature methodSignature = (MethodSignature) signature;
String methodName = methodSignature.getMethod().getName();
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
String domain = request.getHeader("domain"); // 模拟从 request 中获取 token,解析出 domain信息
if (StringUtils.isEmpty(domain)) {
log.error("未从 request 中获取到 domain 信息,接口方法 : {} 校验失败!", methodName);
throw new DomainCheckException("未从 request 中获取到 domain 信息, 校验失败");
}
doCheck(domains, domain, positive, methodName);
} else {
log.info("未配置 domain 校验,校验成功");
}
}
private void doCheck(String[] domains, String domain, boolean isPositive, String methodName) throws DomainCheckException {
if (isPositive) {
for (String domainName : domains) {
if (domain.equals(domainName)) {
log.info("request 中获取的 domain 信息为 : {}, 接口方法 : {} 检验成功!", domain, methodName);
return;
}
}
log.error("request 中获取的 domain 信息与方法配置的不一致,接口方法 : {} 校验失败!", methodName);
throw new DomainCheckException("request 中获取的 domain 信息与方法配置的不一致, 校验失败");
} else {
for (String domainName : domains) {
if (domain.equals(domainName)) {
log.error("request 中获取的 domain 信息为 : {}, 访问接口方法 : {} 不能包含 : {}, 接口校验失败!", domain, methodName ,domain);
throw new DomainCheckException("request 中获取的 domain 信息与方法配置的不一致, 校验失败");
}
}
log.info("request 中获取的 domain 信息为 : {}, 接口方法 : {} 检验成功!", domain, methodName);
}
}
}
Controller类的校验,如果方法上已有相应校验,那么会忽略类上的校验
@RestController
@RequestMapping(value = "/domain")
@DomainCheck(domains = {"pom", "serviceStage"})
public class DomainController {
@GetMapping(value = "/{domain}")
public String domain(@PathVariable("domain") String domainName) {
return domainName;
}
@GetMapping(value = "/class/{domain}")
@DomainCheck(domains = {"pom", "serviceStage"}, isPositive = false)
public String clazz(@PathVariable("domain") String domainName) {
return domainName;
}
}