1、web请求权限认证实现WebMvcConfigurer
@Configuration
public class AclWebConfiguration implements WebMvcConfigurer {
@Autowired
private AclHandlerInterceptor aclHandlerInterceptor;
public AclWebConfiguration() {
}
public void addInterceptors(InterceptorRegistry registry) {
if (this.aclHandlerInterceptor != null) {
registry.addInterceptor(this.aclHandlerInterceptor);
}
}
}
2、增加拦截器获取请求头信息
public class AclHandlerInterceptor implements HandlerInterceptor {
private static final Logger log = AclLoggerFactory.getAclLogger();
private CallerIdExtractorRegistry callerIdExtractorRegistry;
public AclHandlerInterceptor() {
}
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String callerIdHeaderName = (String)this.callerIdExtractorRegistry.get().filter((expr) -> {
return Type.HTTP_HEADER.name().equals(expr.getType());
}).map(CallerIdExtractorExpr::getHttpHeader).orElse((Object)null);
if (StringUtils.isNotBlank(callerIdHeaderName)) {
String header = request.getHeader(callerIdHeaderName);
if (StringUtils.isNotBlank(header)) {
log.debug("get callerId = {} from header = {}", new Object[]{header, callerIdHeaderName});
}
RequestContextHolder.setCallerId(request.getHeader(callerIdHeaderName));
}
RequestContextHolder.setCheckHealth(request.getHeader("ACL_CHECK_HEALTH"));
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
if (RequestContextHolder.isCheckHealth()) {
this.outputHealthResponse(response);
}
RequestContextHolder.clear();
}
private void outputHealthResponse(HttpServletResponse response) throws Exception {
response.setStatus(200);
response.setHeader("content-type", "json/application;charset=UTF-8");
OutputStream outputStream = response.getOutputStream();
outputStream.write(JsonUtils.toJson(new AclHandlerInterceptor.Health()).getBytes(StandardCharsets.UTF_8));
}
public void setCallerIdExtractorRegistry(final CallerIdExtractorRegistry callerIdExtractorRegistry) {
this.callerIdExtractorRegistry = callerIdExtractorRegistry;
}
}
3、构建权限处理器
public class AclInvocationHandler implements InvocationHandler {
private static final Logger log = AclLoggerFactory.getAclLogger();
public static List<String> blacklist = Lists.newArrayList(new String[]{"toString", "getClass", "hashCode", "equals", "clone"});
private Object target;
private MethodAccessControlService methodAccessControlService;
private DataAccessControlService dataAccessControlService;
private RateLimiterService rateLimiterService;
public AclInvocationHandler(Object target, MethodAccessControlService methodAccessControlService, DataAccessControlService dataAccessControlService, RateLimiterService rateLimiterService) {
this.target = target;
this.methodAccessControlService = methodAccessControlService;
this.dataAccessControlService = dataAccessControlService;
this.rateLimiterService = rateLimiterService;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (blacklist.contains(method.getName())) {
return method.invoke(this.target, args);
} else if (RequestContextHolder.isCheckHealth()) {
return this.returnMockValue(method);
} else {
Invocation invocation = null;
try {
invocation = this.buildInvocation(method, args);
this.methodAccessControlService.accessControl(invocation);
} catch (AclException var9) {
throw var9;
} catch (Exception var10) {
log.error("Failed to method access control method={}, args={}", new Object[]{method, args, var10});
}
this.rateLimiterService.limitRate(invocation);
Object returnValue;
try {
returnValue = method.invoke(this.target, args);
} catch (InvocationTargetException var8) {
throw var8.getTargetException();
}
try {
if (invocation != null) {
return this.dataAccessControlService.filter(returnValue, invocation);
}
} catch (Exception var7) {
log.error("Failed to data access control method={}, args={}", new Object[]{method, args, var7});
}
return returnValue;
}
}
protected Object returnMockValue(Method method) {
return method.getReturnType().isPrimitive() ? Primitives.getDefault(method.getReturnType()) : null;
}
protected Invocation buildInvocation(Method method, Object[] args) {
ApplicationService applicationService = (ApplicationService)ReflectUtils.findApplicationService(method).orElse((Object)null);
Assert.notNull(applicationService, "Expect to find one @ApplicationService");
Class<?> intf = (Class)Arrays.stream(method.getDeclaringClass().getInterfaces()).filter((c) -> {
return c.isAnnotationPresent(ApplicationService.class);
}).findFirst().orElseThrow(() -> {
return new IllegalArgumentException("Failed to find interface annotated with @ApplicationService for class=" + method.getDeclaringClass().getName());
});
Invocation invocation = new Invocation();
invocation.setCallerId(RequestContextHolder.getCallerId());
invocation.setDomainName(applicationService.domain());
invocation.setServiceName(intf.getName());
invocation.setArgs(args);
invocation.setMethod(method);
return invocation;
}
}
4、实现BeanPostProcessor,将需要认证的类构建代理类
public class AclBeanPostProcessor implements BeanPostProcessor, BeanFactoryPostProcessor, BeanFactoryAware {
private static final Logger log = AclLoggerFactory.getAclLogger();
private Map<String, Class> asBeanClasses = Maps.newHashMap();
private BeanFactory beanFactory;
public AclBeanPostProcessor() {
}
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return super.postProcessBeforeInitialization(bean, beanName);
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (this.asBeanClasses.containsKey(beanName)) {
MethodAccessControlService methodAccessControlService = (MethodAccessControlService)this.beanFactory.getBean(MethodAccessControlService.class);
DataAccessControlService dataAccessControlService = (DataAccessControlService)this.beanFactory.getBean(DataAccessControlService.class);
RateLimiterService rateLimiterService = (RateLimiterService)this.beanFactory.getBean(RateLimiterService.class);
log.debug("create acl proxy of bean={}", new Object[]{beanName});
return Enhancer.create((Class)this.asBeanClasses.get(beanName), new AclInvocationHandler(bean, methodAccessControlService, dataAccessControlService, rateLimiterService));
} else {
return super.postProcessAfterInitialization(bean, beanName);
}
}
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
try {
if (!(beanFactory instanceof DefaultListableBeanFactory)) {
throw new IllegalStateException("CustomAutowireConfigurer needs to operate on a DefaultListableBeanFactory");
} else {
String[] beanNames = beanFactory.getBeanNamesForAnnotation(ApplicationService.class);
String[] var3 = beanNames;
int var4 = beanNames.length;
for(int var5 = 0; var5 < var4; ++var5) {
String beanName = var3[var5];
if (beanFactory.getBeanDefinition(beanName).getBeanClassName() != null) {
this.asBeanClasses.put(beanName, Class.forName(beanFactory.getBeanDefinition(beanName).getBeanClassName()));
}
}
}
} catch (Throwable var7) {
throw var7;
}
}
public void setBeanFactory(final BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
}
5、读取规则配置
public class LocalConfigListener extends AbstractConfigListener implements InitializingBean {
private static final Logger log = AclLoggerFactory.getAclLogger();
public LocalConfigListener() {
}
public void afterPropertiesSet() throws Exception {
super.afterPropertiesSet();
this.loadOnce();
}
public void loadOnce() {
this.onListenCallerIdExtractor(this.aclProperties.getCallerId());
this.onListenMethodStatements(this.aclProperties.getMethodStatements());
this.onListenDataStatements(this.aclProperties.getDataStatements());
this.onListenWrapperClasses(this.aclProperties.getWrapperClasses());
this.onListenRateLimiterStatements(this.aclProperties.getRateLimiters());
}
}