Superset 用户集成完整方案(iframe方式)
本次集成方案经过个人测试,根据前面2个集成方案的资料,撰写,相关说明由于个人知识水平有限不一定理解准确,有错误的地方环境评论区评论;
1、用户集成方式:
- A系统用户,通过A的某个界面,iframe嵌入
- superset接到用户信息后,在superset系统中查找用户,如果用户存在,则登录,并形成session,如果用户不存在则新增用户,当然如果用户角色发生变化,则更新用户,并redirect 目标地址
- 用户建立后,如何实现行权限设置,显示用户授权的数据?我这里通过建立动态查询语句实现。
- 嵌入后去除嵌入的dashboard的页面头
2、前期准备,参数设置:Superset config配置文件参数,里面的 跨域访问问题 sql中使用参数问题 设置好;
3、具体细节:
(1)iframe问题:
测试用的链接地址如下:http://superset.alibaba.com:9001/login/?username=jiamidadao&userrole=public&redirect=http://iframe.alibaba.com:9001/superset/dashboard/11/
这里会遇到iframe 跟 redirect 后,session丢失问题
这里我个人理解,没有完全理论知识,跨域访问中,使用了iframe会出现session丢失问题,其实也不是丢失,因为iframe框架返回的session,不是iframe嵌入的链接目标网站的session,而是主站(比如A系统,嵌入superet dashboard页面,A系统是主站)的session,所以用户集成的第2部分iframe的superset网站访问后,用户登录成功,返回session是正确返回的,但是当redirect命令到的时候,浏览器执行location重定向,浏览器判断当前系统没有目标网站 http://iframe.alibaba.com:9001/superset/dashboard/11/ 的session(由于登录的session属于主站),所以不会带着前面登录的session,导致登录不成功,又再次返回登录界面,当然如果此时打印g.user会返回匿名用户,所以这里必须解决iframe 的 session 通用性问题:
针对这个问题解决方法如下:A系统即主站系统的域名设置为:main.alibaba.com ; superset系统域名设置为 superset.alibaba.com ;
在superset的配置文件config.py里面设置 SESSION_COOKIE_DOMAIN = ".alibaba.com"
这样设置后,superset登录环境返回的session就会被浏览器再次调用,iframe的redirect 后session问题解决
如果你还有其他方式,请留言;
此处衍生下,在开发环节,没有域名做解析,怎么办?
通过在客户机上设置host 做域名劫持,进而实现:
127.0.0.1 superset.alibaba.com main.alibaba.com
同时,本机上安装代理服务器,比如Apache Tomcat 8.5 Tomcat8 ,安装后,启动,将下面文件放到根目录,命名为aa.html,
<html> <head> <title>dashboard</title> <style type="text/css"> .dashboard { width: 100%; margin: 0 auto; } .dashboard iframe { width: 100%; height: 100%; margin-top: -150px; } </style> </head> <body> <div class="dashboard"> <div class="superset-legacy-chart-nvd3 superset-legacy-chart-nvd3-dist-bar"> <iframe src='http://superset.alibaba.com:9001/login/?username=jiamiyonghu&userrole=public&redirect=http://superset.alibaba.com:9001/superset/dashboard/11/'> </iframe> </div> </div> </body> <script> </script> </html>
然后浏览器访问:http://main.alibaba.com:8080/aa.html
当然访问前,必须要superset启动程序要打开,比如启动后监听的端口号为9001,本地运行;
下面解决第2步:
(2)用户集成代码
在superset目录下,跟config.py一个目录,新建pthon文件,security1.py
from flask import redirect, g, flash, request from flask_appbuilder.security.views import UserDBModelView,AuthDBView from superset.security import SupersetSecurityManager from flask_appbuilder.security.views import expose from flask_appbuilder.security.manager import BaseSecurityManager from flask_login import login_user, logout_user class CustomAuthDBView(AuthDBView): login_template = 'appbuilder/general/security/login_db.html' @expose('/login/', methods=['GET', 'POST']) def login(self): redirect_url = self.appbuilder.get_url_for_index if request.args.get('redirect') is not None: redirect_url = request.args.get('redirect') if request.args.get('username') is not None: user = self.appbuilder.sm.find_user(username=request.args.get('username')) login_user(user, remember=False) return redirect(redirect_url) elif g.user is not None and g.user.is_authenticated(): #注意经过测试,g.user.is_authenticated()似乎不应当加() return redirect(redirect_url) else: flash('Unable to auto login', 'warning') return super(CustomAuthDBView,self).login() class CustomSecurityManager(SupersetSecurityManager): authdbview = CustomAuthDBView def __init__(self, appbuilder): super(CustomSecurityManager, self).__init__(appbuilder)
注意,上面代码只实现了简单的查找用户,可以自己再完善下,比如新增,和更新,并且验证密码,同时主站传过来的可以时token加密的,这里做解密等,都在上面代码里面修改;
在config.py文件里面新增两行代码
from security import CustomSecurityManager CUSTOM_SECURITY_MANAGER = CustomSecurityManager
执行superset init,重启superset系统,权限完成;提醒下,注意第2步中的参数修改问题;
上述security1的代码另外一个参考是
import jwt import json class CustomAuthDBView(AuthDBView): login_template = 'appbuilder/general/security/login_db.html' @expose('/login/', methods=['GET', 'POST']) def login(self): token = request.args.get('token') if not token: token = request.cookies.get('access_token') if token is not None: jwt_payload = jwt.decode(token,'secret',algorithms=['RS256']) user_name = jwt_payload.get("user_name") user = self.appbuilder.sm.find_user(username=user_name) if not user: role_admin = self.appbuilder.sm.find_role('Admin') user = self.appbuilder.sm.add_user(user_name, user_name, 'aimind', user_name + "@aimind.com", role_admin, password = "aimind" + user_name) if user: login_user(user, remember=False) redirect_url = request.args.get('redirect') if not redirect_url: redirect_url = self.appbuilder.get_url_for_index return redirect(redirect_url) else: return super(CustomAuthDBView,self).login() else: flash('Unable to auto login', 'warning') return super(CustomAuthDBView,self).login()
两个相互参考,后面这个是如果用户不存在,通过self.appbuilder.sm.add_user自动添加用户,但是增加的是admin,可以改为增加public或者其他角色,访问的时候直接访问:http://superset.alibaba.com:9001/login/?token=jwt_token&redirect=http://superset.alibaba.com:9001/superset/dashboard/11/ 即可
(3)实现用户行权限设置,根据用户在主站的授权,显示对应数据
- A系统数据库建立数据权限验证数据库,数据库内容就是用户名,用户名对应的事实表访问权限关系,举例:如果用户是依据部门和产品线授权,则权限视图如下:
creatview useraccess as
select 用户名,部门,产品线 from V_用户授权表
至于用户授权表怎么形成,自己根据公司业务情况,自己去写视图;
对于dashboard中使用的数据源,在对应的在datasets中,自定义下sql语句,如:
{% if current_userrole() == 'admin' %} select a.* from sales a {% else %} select a.* from sales a inner join v_用户权限表 b on a.部门=b.部门 and a.产品线=b.产品线 where b.用户名='{{current_username()}}' {% endif %}
至于如何自定义参数及都有哪些参数可用,见Superset实现动态SQL查询
(4)去除嵌入的superset的页面头部不需要的信息:
在主站A上,嵌入页面的css里面写入下面代码:
<style type="text/css"> .dashboard { width: 100%; margin: 0 auto; } .dashboard iframe { width: 100%; height: 100%; margin-top: -150px; } </style>
恭喜你,到此为止,用户集成问题,解决完毕