【Superset】自定义授权认证,接入内部系统二次开发
想要将内部系统认证与superset打通,必须要了解superset的认证体系。
Superset的认证体系
Superset的认证体系可以通过以下几种方式进行配置:
-
基于LDAP认证:Superset可以集成LDAP以验证用户身份。在这种情况下,Superset将根据LDAP中的用户信息进行身份验证,并从LDAP中获取用户属性和组织结构信息。
-
基于OAuth2认证:Superset支持OAuth2认证和授权。在这种情况下,Superset将重定向用户到OAuth2提供商的登录页,并在用户授权时获取访问令牌以进行身份验证。
-
本地认证:Superset还支持本地认证,其中用户可以在Superset中创建帐户并设置密码。在这种情况下,Superset将使用这些凭据来验证用户身份。
无论使用哪种认证方式,管理员都可以控制哪些用户可以访问Superset中的特定资源。例如,可以定义哪些用户可以访问特定的数据源、仪表板或视图。此外,管理员还可以定义角色和权限,以控制用户在Superset中的操作范围。
二次开发,重写认证
系统配置文件: \superset\config.py
配置缓存
在config.py里面配置
Reids_Url = '127.0.0.1'
Reids_Port = 6379# Cache for datasource metadata and query results
DATA_CACHE_CONFIG: CacheConfig = {'CACHE_TYPE': 'redis', # 使用 Redis'CACHE_REDIS_HOST': Reids_Url, # 配置域名'CACHE_REDIS_PORT': Reids_Port , # 配置端口号'CACHE_REDIS_URL': 'redis://' + Reids_Url + ':' + str(Reids_Port)}
配置认证管理类
在config.py里面配置
from superset.custom_sso_security_manager import CustomSsoSecurityManagerCUSTOM_SECURITY_MANAGER = CustomSsoSecurityManager
新建类
自定义视图:MyAuthRemoteUserView
class MyAuthRemoteUserView(AuthRemoteUserView):# this front-end template should be put under the folder `superset/templates/appbuilder/general/security`# so that superset could find this templates to renderlogin_template = 'appbuilder/general/security/login_my.html'title = "My Login"@expose('/test', methods=['GET', 'POST'])def test(self):data = {}# for name in request.environ:# if (type(request.environ[name]) == str or type(request.environ[name]) == int):# data[name] = request.environ[name]# return dataresponse = _wz_redirect('/login/')print(response.headers)return response# this method is going to overwrite# https://github.com/dpgaspar/Flask-AppBuilder/blob/master/flask_appbuilder/security/views.py#L556@expose('/login/', methods=['GET', 'POST'])def login(self):next_url = get_real_scheme_next_url()if g.user and g.user.get_id():return redirect(next_url)token= request.cookies.get("token")if (tokenNone or token== ''):print("token未获取到!")return redirect(CustomSsoSecurityManager.CAS_LOGIN_SERVER_URL + "?redirect_uri=" + self.get_login_redirect_uri())manager = self.appbuilder.smheader = {"cookie": "token=" + userToken,}result = requests.post(CustomSsoSecurityManager.CAS_CHECK_SERVER_URL,headers=header)resultWarp = json.loads(result.content)if (not resultWarp["success"]):return redirect(CustomSsoSecurityManager.CAS_LOGIN_SERVER_URL + "?redirect_uri=" + self.get_login_redirect_uri())cas_user = resultWarp["result"]username = cas_user['username']user = manager.find_user(username=username)print(user)# User does not exist, create one if auto user registration.if user is None and manager.auth_user_registration:user = manager.add_user(# All we have is REMOTE_USER, so we set# the other fields to blank.username=username,first_name=cas_user['name'],last_name='',email=username,role=manager.find_role(manager.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 Nonemanager.update_user_auth_stat(user)login_user(user, remember=False)session[SESSION_CAS_USER] = cas_usersession[SESSION_HCP] = hcpCustomSsoSecurityManager.get_data_auth(hcp, cas_user['id'])return redirect(next_url)def get_Login_url(self):return get_root_url() + '/login/'def get_login_redirect_uri(self):next_url = get_real_scheme_next_url()return parse.quote(self.get_Login_url() + "?next=" + next_url)@expose("/logout/")def logout(self):logout_user()userToken= request.cookies.get("token")if userToken:header = {"cookie": "token=" + userToken,}data = {"token": hcp}requests.post(CustomSsoSecurityManager.CAS_LOGINOUT_SERVER_URL, json=data,headers=header)if CustomSsoSecurityManager.SESSION_CAS_USER in session:session.pop(CustomSsoSecurityManager.SESSION_CAS_USER)if CustomSsoSecurityManager.SESSION_HCP in session:session.pop(CustomSsoSecurityManager.SESSION_HCP)if CustomSsoSecurityManager.SESSION_CAS_DATA_AUTH in session:session.pop(CustomSsoSecurityManager.SESSION_CAS_DATA_AUTH)return redirect(CustomSsoSecurityManager.CAS_LOGIN_SERVER_URL + '?redirect_uri=' + self.get_Login_url())
自定义管理类:CustomSsoSecurityManager
class CustomSsoSecurityManager(SupersetSecurityManager):authremoteuserview = MyAuthRemoteUserViewSESSION_CAS_USER = "_CAS_USER"SESSION_CAS_DATA_AUTH = "_CAS_DATA_AUTH"CAS_LOGIN_SERVER_URL = NoneCAS_CHECK_SERVER_URL = NoneCAS_LOGINOUT_SERVER_URL = NoneCAS_DATA_AUTH_URL = Noneconfig = Nonedef __init__(self, appbuilder):super().__init__(appbuilder)CustomSsoSecurityManager.get_cas_url(appbuilder.app.config)@classmethoddef get_cas_url(cls, config):cls.config = configcls.CAS_LOGIN_SERVER_URL = cls.config.get("SSO_LOGIN_URL")cls.CAS_CHECK_SERVER_URL = cls.config.get("SSO_SERVER_API_URL") + '/getCurrentUser'cls.CAS_LOGINOUT_SERVER_URL = cls.config.get("SSO_SERVER_API_URL") + '/logout'cls.CAS_DATA_AUTH_URL = cls.config.get("SSO_SERVER_API_URL") + '/getDataAuthByUserId'# 获取数据权限@classmethoddef get_data_auth(cls, token, user_id):data = {"moduleId": "SAAS_BI_DATA_AUTHORITY", "userId": user_id}result = requests.post(cls.CAS_DATA_AUTH_URL, json=data,headers=header)# print(result.content)result_warp = json.loads(result.content)if (not result_warp["success"]):else:session[cls.SESSION_CAS_DATA_AUTH] = result_warp['result']def load_user(self, pk):return self.get_user_by_id(int(pk))def setCache(self, key, value, expire):r.set(key, value)if expire is None or expire < 10:expire = 60 * 5r.expire(key, expire)def load_user3(self):token= request.cookies.get("token")biUserCacheData = {}if (tokenis None or token== ''):user = self.lm.anonymous_user()return self.lm._update_request_context_with_user(user)biUserKey = tokenbiUserInfoCache = NoneuserCache = NonebiUserCacheData = Noneif r.hexists(biUserKey, "apiUserInfo"):biUserInfoCache = r.hget(biUserKey, "apiUserInfo")userCache = biUserInfoCache.decode()biUserCacheData = json.loads(userCache)if biUserCacheData["success"] == False:biUserInfoCache = Noneif biUserInfoCache:cas_user = biUserCacheData["result"]session[CustomSsoSecurityManager.SESSION_CAS_USER] = cas_usersession[CustomSsoSecurityManager.SESSION_HCP] = tokenusername = cas_user['username']manager = self.appbuilder.smuser = manager.find_user(username=username)apiUserAuth = r.hget(biUserKey, "apiUserAuth")result_warp = json.loads(apiUserAuth.decode())if (not result_warp["success"]):user = self.lm.anonymous_user()return self.lm._update_request_context_with_user(user)else:session[self.SESSION_CAS_DATA_AUTH] = result_warp['result']else:manager = self.appbuilder.smheader = {"cookie": "token=" + token}result = requests.post(CustomSsoSecurityManager.CAS_CHECK_SERVER_URL,headers=header)resultWarp = json.loads(result.content)r.hset(biUserKey, "apiUserInfo", result.content)if (not resultWarp["success"]):user = self.lm.anonymous_user()return self.lm._update_request_context_with_user(user)cas_user = resultWarp["result"]username = cas_user['username']user = manager.find_user(username=username)# User does not exist, create one if auto user registration.if user is None and manager.auth_user_registration:user = manager.add_user(# All we have is REMOTE_USER, so we set# the other fields to blank.username=username,first_name=cas_user['name'],last_name='',email=username,role=manager.find_role(manager.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))user = self.lm.anonymous_user()return self.lm._update_request_context_with_user(user)manager.update_user_auth_stat(user)login_user(user, remember=False)session[CustomSsoSecurityManager.SESSION_CAS_USER] = cas_usersession[CustomSsoSecurityManager.SESSION_HCP] = tokenheader = {"cookie": "token=" + token}data = {"moduleId": "SAAS_BI_DATA_AUTHORITY", "userId": cas_user['id']}result = requests.post(self.CAS_DATA_AUTH_URL, json=data,headers=header)# print(result.content)result_warp = json.loads(result.content)r.hset(biUserKey, "apiUserAuth", result.content)if (not result_warp["success"]):user = self.lm.anonymous_user()return self.lm._update_request_context_with_user(user)else:session[self.SESSION_CAS_DATA_AUTH] = result_warp['result']return self.lm._update_request_context_with_user(user)def create_login_manager(self, app: Flask) -> LoginManager:lm = super().create_login_manager(app)lm.request_loader(self.request_loader)lm._load_user = self.load_user3self.lm = lmreturn lm@classmethoddef get_data_auth_from_session(cls):return session[cls.SESSION_CAS_DATA_AUTH]@classmethoddef get_cas_user_from_session(cls):return session[cls.SESSION_CAS_USER]
参考资料:
- zhuanlan.zhihu.com/p/516553212
相关文章:

【Superset】自定义授权认证,接入内部系统二次开发
想要将内部系统认证与superset打通,必须要了解superset的认证体系。 Superset的认证体系 Superset的认证体系可以通过以下几种方式进行配置: 基于LDAP认证:Superset可以集成LDAP以验证用户身份。在这种情况下,Superset将根据LDAP…...

私有云:【1】ESXI的安装
私有云:【1】ESXI的安装 1、使用VMware Workstation创建虚拟机2、启动配置虚拟机3、登录ESXI管理台 1、使用VMware Workstation创建虚拟机 新建虚拟机 选择典型安装 稍后安装操作系统 选择VMware ESXI 选择虚拟机安装路径 硬盘设置300G或者更多 自定义硬件 内存和处…...

Mac怎么删除文件和软件?苹果电脑删除第三方软件方法
Mac删除程序这个话题为什么一直重复说或者太多人讨论呢?因为如果操作不当,可能会导致某些不好的影响。因为Mac电脑如果有太多无用的应用程序,很有可能会拖垮Mac系统的运行速度。或者如果因为删除不干净,导致残留文件积累在Mac电脑…...

【开题报告】基于微信小程序的旅游攻略分享平台的设计与实现
1.研究背景及意义 旅游已经成为现代人生活中重要的组成部分,人们越来越热衷于探索新的目的地和体验不同的文化。然而,对于旅游者来说,获取准确、可靠的旅游攻略信息并不容易。传统的旅游攻略书籍或网站往往无法提供实时、个性化的建议。因此…...

布隆过滤器(Bloom Filter)初学习
目录 1、布隆过滤器是什么 2、布隆过滤器的优缺点 3、使用场景 4、⭐基于Redis的布隆过滤器插件安装 4.1 下载布隆过滤器 4.2 创建文件夹并上传文件 4.3 安装gcc 4.4 解压RedisBloom压缩包 4.5 在解压好的文件夹下输入make 4.6 将编译的好的插件拷贝到docker redis容…...

“深入探讨操作系统和虚拟化技术“
目录 引言1.操作系统1.1.什么是操作系统1.2.常见操作系统1.3.个人版本和服务器版本的区别1.4.Linux的各个版本 2.安装VMWare虚拟机1.VMWare虚拟机介绍2.VMWare虚拟机安装3.VMWare虚拟机配置 3.安装配置Windows Server 2012 R24.完成电脑远程访问电脑5.服务器环境搭建配置jdk配置…...

远程连接异地主机可能遇到的问题及处理
0.现状 公司的一套系统内部有多个节点的内网,要把数据上传至客户的办公网环境中的服务器。客户办公网为我们提供了一台类似路由的设备,办公网无法让内网地址的数据包透传至服务器。现场条件所限,只有有限数量的技术服务人员可以维持…...

使用 PointNet 进行3D点集(即点云)的分类
点云分类 介绍 无序3D点集(即点云)的分类、检测和分割是计算机视觉中的核心问题。此示例实现了开创性的点云深度学习论文PointNet(Qi 等人,2017)。 设置 如果使用 colab 首先安装 trimesh !pip install trimesh。 import os import glob import trimesh import numpy as…...

高通平台GPIO引脚复用指导
高通平台GPIO引脚复用指导 1. 概述1.1 平台有多少个GPIO?1.2 这些GPIO都有哪些可复用的功能? 2. 软件配置2.1 TZ侧GPIO配置2.2 SBL侧GPIO配置2.3 AP侧GPIO配置2.3.1 Linux DTS机制与设备驱动模型概述2.3.2高通平台的pinctrl控制器2.3.2.1 SDX12 CPU pinc…...

华为机试题:HJ5 进制转换
目录 第一章、算法题1.1)题目描述1.2)解题思路与答案1.3)派仔的解题思路与答案1.3)牛客链接 友情提醒: 先看文章目录,大致了解文章知识点结构,点击文章目录可直接跳转到文章指定位置。 第一章、算法题 1.…...

面试算法37:小行星碰撞
题目 输入一个表示小行星的数组,数组中每个数字的绝对值表示小行星的大小,数字的正负号表示小行星运动的方向,正号表示向右飞行,负号表示向左飞行。如果两颗小行星相撞,那么体积较小的小行星将会爆炸最终消失…...

ROS学习记录2018.7.10
ROS学习记录2018.7.10 1.ROS基础了解 开源机器人操作系统ROS(robot operation system) 分级: 1.计算图集(一种网络结构) 1.节点:执行运算的进程(做基础处理的单元)2.消息&#x…...

OPC UA:工业领域的“HTML”
OPC UA是工业自动化领域的一项重要的通信协议。它的特点是包括了信息模型构建方法。能够建立工业领域各种事物的信息模型。在工业自动化行业,OPCUA 类似互联网行业的HTTP协议和“HTML”语言。能够准确,可靠地描述复杂系统中各个元素,并且实现…...

【golang】Windows环境下Gin框架安装和配置
Windows环境下Gin框架安装和配置 我终于搞定了Gin框架的安装,花了两三个小时,只能说道阻且长,所以写下这篇记录文章 先需要修改一些变量,这就需要打开终端,为了一次奏效,我们直接设置全局的: …...

多测师肖sir_高级金牌讲师__接口测试之tonken (5.6)
接口测试之tonken 网站:http://shop.duoceshi.com/login?redirect2Fdashboard 第一个接口:uiid接口 uiid接口url:http://manage.duoceshi.com/auth/code test中语句: var jsonData JSON.parse(responseBody); postman.setEnvi…...

C++常见面试问题之内存对齐
一、内存对齐是什么 1.内存对齐是什么 还是用一个例子带出这个问题,看下面的小程序,理论上,32位系统下,int占4byte,char占一个byte,那么将它们放到一个结构体中应该占415byte;但是实际上&…...

网络协议--TCP:传输控制协议
17.1 引言 本章将介绍TCP为应用层提供的服务,以及TCP首部中的各个字段。随后的几章我们在了解TCP的工作过程中将对这些字段作详细介绍。 对TCP的介绍将由本章开始,并一直包括随后的7章。第18章描述如何建立和终止一个TCP连接,第19和第20章将…...

网络协议--BOOTP:引导程序协议
16.1 引言 在第5章我们介绍了一个无盘系统,它在不知道自身IP地址的情况下,在进行系统引导时能够通过RARP来获取它的IP地址。然而使用RARP有两个问题:(1)IP地址是返回的唯一结果;(2)…...

33基于MATLAB的对RGB图像实现中值滤波,均值滤波,维纳滤波。程序已通过调试,可直接运行。
基于MATLAB的对RGB图像实现中值滤波,均值滤波,维纳滤波。程序已通过调试,可直接运行。 33 MATLAB、图像处理、维纳滤波 (xiaohongshu.com)...

WPF十六(页面内嵌加载)
在WPF中进行页面内嵌的加载 当存在一定需求时,比如当前页面C左侧是一个A页面,右侧是一个B页面,A页面是一个公用页面时,此时只需要做内嵌A页面,然后B页面进行正常处理,既可以节省时间,又做到了WP…...

JAVA基础(JAVA SE)学习笔记(九)异常处理
前言 1. 学习视频: 尚硅谷Java零基础全套视频教程(宋红康2023版,java入门自学必备)_哔哩哔哩_bilibili 2023最新Java学习路线 - 哔哩哔哩 第三阶段:Java高级应用 9.异常处理 10.多线程 11.常用类和基础API 12.集合框架 13.泛型 14…...

Miniconda、Vscode下载和conda源、pip源设置
1、常用软件下载 1、Miniconda软件下载: windows网址:https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/?CS&OA 2、最新版Miniconda下载网址:https://docs.conda.io/projects/miniconda/en/latest/ 3、常用代码编辑器VsCode下…...

CAN接口的PCB Layout规则要求汇总
随着时代高速发展,控制器局域网(CAN)接口的应用越来越广泛,尤其是在汽车电子、航空航天等领域中发挥着重要作用,为了确保CAN接口的可靠性和稳定性,工程师必须在其PCB Layout方面下功夫,下面来看…...

IP网络矿用打点紧急广播方案
IP网络矿用打点紧急广播方案 一、概述 目前,随着计算机网络技术的迅速普及,信息化已经走向煤矿。很多煤矿都陆续具有了稳定可靠、覆盖矿井上下的工业以太网。科学技术的不断进步和信息化矿山建设步伐的不断加快,井下工业以太网将逐渐得到推…...

系列六、FactoryBean vs ApplicationContext
一、FactoryBean vs ApplicationContext 1.1、概述 BeanFactory是一个工厂类,负责生产和管理bean,在Spring中BeanFactory是IOC容器的核心接口,它的主要职责就是生产bean及建立各个bean之间的依赖。applicationContext是BeanFactory的一个子接…...

AOP简单使用模版
AOP面向切面编程 切面类的定义之模版 package com.xie.service;import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.*; import org.aspectj.lang.ProceedingJoinPoint; import org.springframework.stereotype.Component; import javax.servlet.http.Http…...

手机注册.
<!DOCTYPE html> <html><head><title>注册</title><meta http-equiv"content-type" content"text/html; charsetutf-8"/><meta name"apple-mobile-web-app-capable" content"yes"/><lin…...

PostgreSQL 17新特性之登录事件触发器
PostgreSQL 9.3 就提供了事件触发器功能,可以基于 DDL 语句触发相应的操作。 正在开发中的 PostgreSQL 17 增加了基于登录事件的触发器,可以在用户登录时执行某些检查或者特定操作。登录事件触发器的使用方法和其他触发器一样:创建一个返回 …...

Docker 搭建 LNMP + Wordpress
[TOC](Docker 搭建 LNMP Wordpress 一、项目介绍1.1、项目环境1.2、 服务器环境1.3、 任务需求 二、部署Nginx2.1、建立工作目录2.2、 编写 Dockerfile 脚本2.3、准备 nginx.conf 配置文件2.4、生成镜像2.5、创建自定义网络 三、部署Mysql3.1、建立工作目录3.2、编写 Dockerfi…...

大数据调度最佳实践 | 从Airflow迁移到Apache DolphinScheduler
迁移背景 有部分用户原来是使用 Airflow 作为调度系统的,但是由于 Airflow 只能通过代码来定义工作流,并且没有对资源、项目的粒度划分,导致在部分需要较强权限控制的场景下不能很好的贴合客户需求,所以部分用户需要将调度系统从…...