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>

恭喜你,到此为止,用户集成问题,解决完毕

posted @ 2021-08-16 15:15  数据行者  阅读(6354)  评论(4编辑  收藏  举报