权限认证解决方案

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());
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值