BI工具——superset(master)选择性加入JWT验证

2020-03-14  本文已影响0人  安森老叔叔

开干

这个标题挺有意思——“选择性”,那也就是说,业务上要只对部分接口做鉴权,而上篇在 CustomSecurityManager 中做的修改则是针对接口全局的修改,在这个需求面前经不住考究。
在“最小改动”和“支持扩展”、“方便维护”原则下,肯定是要继续读源码的。
假设我现在是需要做iframe中链接的鉴权,那相关的接口就是/explore和/explore_json,我的做法也相对明确——通过装饰器实现。

首先先了解下闭包和装饰器。推荐看:https://www.cnblogs.com/linxiyue/p/11224322.html

一个典型的装饰器如下:

def deco(func):
    def new_func(*args, **kwargs):
        return func(*args, **kwargs)
    return new_func

我们需要在调用原接口处理逻辑之前,先进行我们的验证——具体操作就是把我们的装饰器@到/explore上,当判断到是在加载iframe内容时,装饰器发生作用。
同理地,我们看一段权限校验的源码👇

def has_access(f):
    if hasattr(f, '_permission_name'):
        permission_str = f._permission_name
    else:
        permission_str = f.__name__

    def wraps(self, *args, **kwargs):
        permission_str = PERMISSION_PREFIX + f._permission_name
        if self.appbuilder.sm.has_access(permission_str, self.__class__.__name__):
            return f(self, *args, **kwargs)
        else:
            log.warning(LOGMSG_ERR_SEC_ACCESS_DENIED.format(permission_str, self.__class__.__name__))
            flash(as_unicode(FLAMSG_ERR_SEC_ACCESS_DENIED), "danger")
        return redirect(url_for(self.appbuilder.sm.auth_view.__class__.__name__ + ".login"))
    f._permission_name = permission_str
    return functools.update_wrapper(wraps, f)

最终我们的装饰器函数如下👇

def has_iframe_access(f):
    def wraps(self, *args, **kwargs):
        authorization = request.headers.get("Authorization")
        v = request.args.get("standalone")

        if request.method == "GET" and v == "true":
            if authorization:
                token = authorization.split(" ")[1]
                payload = auth.verify_jwt(token)
                if type(payload) == dict:
                    return f(self, *args, **kwargs)
                else:
                    response = make_response(jsonify({'message': "token expired"}), 401)
                    response.headers['Content-Type'] = "application/json"
                    return response
            else:
                response = make_response(jsonify({'message': "access denied"}), 401)
                response.headers['Content-Type'] = "application/json"
                return response
        else:
            return f(self, *args, **kwargs)

    return functools.update_wrapper(wraps, f)

先解决如何匿名访问iframe上的数据,记得在界面上操作一下用户角色权限(再次操作时我忘了,找了好久):https://blog.csdn.net/a303944689/article/details/78739269

你会发现当我们把装饰器给/explore接口加上的时候,如果没有根据协议来携带参数访问,在浏览器中访问如下链接时

http://127.0.0.1:9000/superset/explore/?form_data={"slice_id":2216}&standalone=true&height=400

服务器直接拒绝掉了,甚至都还没把后面的两个参数给去掉。
把参数加上后,即可。

上一篇 下一篇

猜你喜欢

热点阅读