Superset登录权限二次开发

Superset简介

Superset是Airbnb开源的一个数据可视化工具, 可以接入Druid, Presto, Kylin等数据库或查询引擎. 提供丰富的可视化效果, 支持TB级别的数据量查询. Superset使用Flask-Appbuilder作为后端的开发框架, 提供更加灵活的登录, 权限管理, view等定制化功能, 方便整合自己的系统以及二次开发. Superset解决了企业报表开发流程繁琐, 权限管理混乱的问题.

这篇文章手把手教你如何对Superset的登陆权限模块进行二次开发!版本虽然比较旧,但听很多同学反馈稍微改动一下就能用~

Superset 代码结构

从github下载源码后, 打开文件夹, 主要的代码逻辑都在superset路径下.
如果是通过pip 安装的, 通过which superset可查看可执行文件所在路径/usr/local/lib/python2.7/site-packages/superset, 该路径下的文件和源码一致, 如下所示.

Superset代码结构

  • superset/bin: 该目录下的superset文件为程序的执行入口, 可以在项目根目录执行python superset/bin/superset runserver启动superset后台. 实际上调用了superset/cli.py
  • superset/connectors: superset的一些数据源, table的model和view, 可以理解为接入数据源相关的控制代码
  • superset/migration: 存放superset database schema升级和版本变迁, 所有的数据库修改都需要走migration, 升级的时候需要执行superset db upgrade && superset db init
  • superset/models: 存放superset的数据库模型, superset的核心逻辑如Slice, Dashboard都可以在这里找到. 可以理解为后端的模型代码都放在这边.
  • superset/staticsuperset/templates: superset前端相关的模板, 控件代码全部在该目录下, 如果需要对superset的前端进行编译, 需要执行npm run dev, 编译后的前端代码不会出现本地代码后台启动后css没效果等情况.
  • superset/views: 放置superset所有的视图, 关于Slice, Dashboard和SQL Lab相关的展示, 查询, 存储, 下载等功能可以查看这里面的源码. 前端相关的交互, API都可以到views目录下查看.
  • superset/__init__.py: 这里包含了Flask APP, Flask AppBuilder, SQLAlchemy, 和Security Manager的启动工作, 启动了superset的视图, 数据库连接, 安全管理等.

通过阅读superset/config.py中的代码, 如果需要自行修改配置, 创建superset_config.py文件, 并把该文件的路径export到环境变量SUPERSET_CONFIG_PATH中.

登录权限自定义开发

Superset登录模块其实是使用了F.A.B(Flask-AppBuilder的简称)的登录认证框架. 有以下的登录认证方式:

AUTH_TYPE value description
0 / AUTH_OID Open ID的方式验证, 比如通过gmail, Twitter, FB第三方APP都属于这个范畴
1 / AUTH_DB 通过用户名密码的方式登录, 登录信息存到数据库
2 / AUTH_LDAP 通过LDAP协议进行登录授权, 感兴趣可以搜一下LDAP协议
3 / AUTH_REMOTE_USER 从web server中获得验证, 该server可以是公司内统一使用的登陆系统
4 / AUTH_OAUTH superset不支持该配置方法

以上更详细的内容可以查阅F.A.B的SecurityManager源码

对Superset的源码进行熟悉后, 在superset/config.py中有AUTHENTICATION CONFIG配置, 将AUTH_TYPE的值写到superset_config.py并告诉superset该文件的路径, 这样就能够把自己想要修改的配置对superset源码中的配置进行替换. 我将自己写的配置信息写到~/superset/conf/superset_config.py

export SUPERSET_CONFIG_PATH=~/superset/conf/superset_config.py

AUTH_REMOTE_USER 开发

在公司的日常生产中, 新增一个系统, 登录模块一般会为了统一和安全考虑, 使用员工现有邮箱和密码作为登录方式, 也就是通过调用remote server API(比如邮箱验证的API)的方式, 获取用户的认证信息, 认证通过就将用户信息保存到db中, 只要用户的session没有过期, 下次就可以直接访问网站. 即上面所说的AUTH_REMOTE_USER方式.

1. 配置

首先在superset_config.py中配置CUSTOM_SECURITY_MANAGER, 替换superset中使用的SecurityManager. 接下来写一个MySecurityManager类去继承SecurityManager, 重写一些view和方法来定制自己想要的登录效果.

from flask_appbuilder.security.manager import AUTH_REMOTE_USER
from security.security_models import MySecurityManager

# using customize MY security manager
CUSTOM_SECURITY_MANAGER = MySecurityManager

# AUTHENTICATION CONFIG
# 使用remote server的方式进行认证
AUTH_TYPE = AUTH_REMOTE_USER

# setup Public role name, no authentication needed
AUTH_ROLE_PUBLIC = 'Gamma'

# Will allow user self registration
AUTH_USER_REGISTRATION = True

2. 继承和重写

Flask-Appbuilder中管理安全相关的类是SecurityManager, 正如该类的描述:

Responsible for authentication, registering security views, role and permission auto management. If you want to change anything just inherit and override, then pass your own security manager to AppBuilder.

它负责认证, 注册安全相关的视图, 角色和权限自动化管理.
所以开发的思路是屡清楚它的继承关系, 看看有哪些view, model或者方法是可以进行重写的, 从而实现自己想要的效果.

  • view可以简单理解为界面上可以看到的东西, model可以理解为和数据库交互相关的模型.
  • 这里还涉及面向对象, 继承, 重写等概念, 不太清楚的同学推荐阅读<Java编程思想>, 里面对面向对象讲的非常棒!
SecurityManager继承关系图

这个过程中我着重看了auth_remote_user相关的处理逻辑, 重写了authremoteuserview对象以及login的方法. 具体查看代码:

# -*- coding: utf-8 -*-
import logging

from flask_appbuilder.const import LOGMSG_WAR_SEC_LOGIN_FAILED
from flask_appbuilder.security.sqla.manager import SecurityManager

from security.security_views import MyAuthRemoteUserView

logger = logging.getLogger(__name__)

# 通过继承SecurityManager, 创建MySecurityManager类
class MySecurityManager(SecurityManager):
    logger.info("using customize my security manager")
    # 重写auth remote user view来实现登录界面的逻辑控制
    # MyAuthRemoteUserView的具体代码可以查看github链接
    authremoteuserview = MyAuthRemoteUserView

    # 这个方法是通过查看SecurityManager源码中
    # 对auth_db等方法的操作逻辑, 自己稍作修改而来
    def auth_user_remote_user(self, username):
        """
            this is a overwrite method
            
            REMOTE_USER user Authentication
            :type self: User model
        """
        user = self.find_user(username=username)

        # User does not exist, create one if auto user registration.
        if user is None and self.auth_user_registration:
            user = self.add_user(
    # All we have is REMOTE_USER, so we set
    # the other fields to blank.
                username=username,
                first_name=username.split('@')[0],
                last_name='-',
                email=username,
                role=self.find_role(self.auth_user_registration_role))

        # If user does not exist on the DB and not auto user registration,
        # or user is inactive, go away.
        elif user is None or (not user.is_active()):
            logger.info(LOGMSG_WAR_SEC_LOGIN_FAILED.format(username))
            return None
            
        self.update_user_auth_stat(user)
        return user
  • MyAuthRemoteUserView: 这个实现的逻辑也比较简单, 我是希望能够通过邮箱和密码登录, 检查form提交数据是否准确, 重写login endpoint. 这过程中使用的LoginForm非常好用, 也想多说几句, 这是Flask提供的widget, 可以检查用户提交的字段是否正确(比如email格式是否正确), 设置required项等功能.

以上的代码demo我已经提交到github https://github.com/yamyamyuo/superset-development, 不知道我写的对大家有没有帮助, 如果有不清楚的地方, 欢迎在留言区讨论~~

结语

拖了好久, 终于把这篇文章整理出来了. 这段时间一直在看superset的源码, 感觉进步不少, 阅读源码果然是提高代码能力的利器~


2022.05.16 更新
如果你对 Superset 的二次开发方面有问题,看我个人简介,可以找到联系我的方式
最近准备输出更多的superset实践经验,欢迎持续关注

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容