Superset是Airbnb開源的一個數據可視化工具, 能夠接入Druid, Presto, Kylin等數據庫或查詢引擎. 提供豐富的可視化效果, 支持TB級別的數據量查詢. Superset使用Flask-Appbuilder做爲後端的開發框架, 提供更加靈活的登陸, 權限管理, view等定製化功能, 方便整合本身的系統以及二次開發. Superset解決了企業報表開發流程繁瑣, 權限管理混亂的問題.前端
從github下載源碼後, 打開文件夾, 主要的代碼邏輯都在superset
路徑下. 若是是經過pip 安裝的, 經過which superset
可查看可執行文件所在路徑/usr/local/lib/python2.7/site-packages/superset
, 該路徑下的文件和源碼一致, 以下所示. python
superset/bin
: 該目錄下的superset
文件爲程序的執行入口superset/connectors
: superset的一些數據源, table的model和viewsuperset/migration
: 存放superset db schema升級和版本變遷superset/models
: 存放superset的數據庫模型, superset的核心邏輯如Slice, Dashboard均可以在這裏找到.superset/static
和 superset/templates
: superset前端相關的模板, 控件代碼superset/views
: 放置superset全部的視圖, 關於Slice, Dashboard和SQL Lab相關的展現, 查詢, 存儲, 下載等功能能夠查看這裏面的源碼.superset/__init__.py
: 這裏包含了Flask APP, Flask AppBuilder, SQLAlchemy, 和Security Manager的啓動工做, 啓動了superset的視圖, 數據庫鏈接, 安全管理等.經過閱讀superset/config.py
中的代碼, 若是須要自行修改配置, 建立superset_config.py
文件, 並把該文件的路徑export到環境變量SUPERSET_CONFIG_PATH
中.git
Superset登陸模塊實際上是使用了F.A.B(Flask-AppBuilder的簡稱)的登陸認證框架. 有如下的登陸認證方式:github
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源碼web
對Superset的源碼進行熟悉後, 在superset/config.py
中有AUTHENTICATION CONFIG配置, 將AUTH_TYPE
的值寫到superset_config.py
並告訴superset該文件的路徑, 這樣就可以把本身想要修改的配置對superset源碼中的配置進行替換. 我將本身寫的配置信息寫到~/superset/conf/superset_config.py
sql
export SUPERSET_CONFIG_PATH=~/superset/conf/superset_config.py
複製代碼
在公司的平常生產中, 新增一個系統, 登陸模塊通常會爲了統一和安全考慮, 使用員工現有郵箱和密碼做爲登陸方式, 也就是經過調用remote server API(好比郵箱驗證的API)的方式, 獲取用戶的認證信息, 認證經過就將用戶信息保存到db中, 只要用戶的session沒有過時, 下次就能夠直接訪問網站. 即上面所說的AUTH_REMOTE_USER
方式.數據庫
首先在superset_config.py中配置CUSTOM_SECURITY_MANAGER
, 替換superset中使用的SecurityManager. 接下來寫一個MySecurityManager
類去繼承SecurityManager, 重寫一些view和方法來定製本身想要的登陸效果.apache
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
複製代碼
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.flask
它負責認證, 註冊安全相關的視圖, 角色和權限自動化管理. 因此開發的思路是屢清楚它的繼承關係, 看看有哪些view, model或者方法是能夠進行重寫的, 從而實現本身想要的效果.
這個過程當中我着重看了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
複製代碼
以上的代碼demo我已經提交到githubhttps://github.com/yamyamyuo/superset-development, 不知道我寫的對你們有沒有幫助, 若是有不清楚的地方, 歡迎在留言區討論~~
拖了很久, 終於把這篇文章整理出來了. 這段時間一直在看superset的源碼, 感受進步很多, 閱讀源碼果真是提升代碼能力的利器~
若是本文對你有幫助
請不要吝嗇你的點贊和關注~
我會繼續總結更新🍻