您现在的位置是:首页 >技术教程 >Superset整合keycloak系统网站首页技术教程

Superset整合keycloak系统

xxb249 2023-06-13 04:00:03
简介Superset整合keycloak系统

本篇主要介绍superset如何整合单点登陆系统keycloak,现在网上的博客大部分都是失效了,这里我相当于更新一下,避免大家再走弯路

一、环境配置

Macos

keycloak:18.0.0

superset:2.1.0

keycloak规定:每一个要接入keycloak的三方系统必须要有一个client与之相对应,所以上来就要创建一个,假设名字为superset

最后对client进行配置,主要包括url设置,具体如下:

二、代码配置

这部分内容在网上大部分都是过期的,基于网上的博客,进行部分依赖库的修改,这里是用macos进行开发,环境部署在linux docker容器中,以下是我修改的文件列表:

 下面分别一个一个将代码进行展示出来:

2.1、Makefile

主要增加环境变量,指定PYTHONPATH所在目录,目的是后面增加文件后能找到变量声明

# 环境变量配置,env,在Makefile 开头附近加上就可以
CUR_DIR:=$(shell pwd)
export PYTHONPATH=$(CUR_DIR)/superset

2.2、base.txt & development.txt

在base.txt增加依赖:

Flask-OpenID==1.3.0
flask-oidc-ext==1.4.5

在development.txt修改依赖:

requests==2.26.0 ==> requests==2.28.2

2.3、superset/config.py

修改AUTH_TYPE = AUTH_DB ==> AUTH_TYPE = AUTH_OID

2.4、新增superset/client_secret.json

{
  "web": {
     "issuer": "https://sso.test.com/auth/realms/master",
     "auth_uri":"https://sso.test.com/auth/realms/master/protocol/openid-connect/auth",
     "client_id": "superset",
     "client_secret": "这个key是从keycloak中web界面里面有提供",
     "verify_ssl_server": false,
     "post_logout_redirect_uri": "http://superset.test.com/",
     "userinfo_uri":"https://sso.test.com/auth/realms/master/protocol/openid-connect/userinfo",
     "token_uri":"https://sso.test.com/auth/realms/master/protocol/openid-connect/token",
     "token_introspection_uri":"https://sso.test.com/auth/realms/master/protocol/openid-connect/token/introspect"
    }
}

2.5、新增superset/superset_config.py

import os
from superset.keycloak_sso import OIDCSecurityManager

#---------------------------------------------------------
# Flask App Builder configuration
#---------------------------------------------------------
# Your App secret key,这个地方SECRET_KEY,需要是随机字符串,代表当前superset app
# 此处的key,和上文中client key不一样
SECRET_KEY='IKyZMVz0hz+Uq097CmD22ghww8oxYvot4yFj2dy3'
OIDC_CLIENT_SECRETS = os.path.dirname(os.path.realpath(__file__)) + '/client_secret.json'
OIDC_ID_TOKEN_COOKIE_SECURE = False
OIDC_REQUIRE_VERIFIED_EMAIL = False
AUTH_USER_REGISTRATION = True
AUTH_USER_REGISTRATION_ROLE = 'Public'
CUSTOM_SECURITY_MANAGER = OIDCSecurityManager
OVERWRITE_REDIRECT_URI = 'http://superset.test.com/oidc_callback'

2.6、新增superset/keycloak_sso.py

import logging
import json
from flask_appbuilder.security.manager import AUTH_OID
from superset.security import SupersetSecurityManager
from flask_appbuilder.security.views import AuthOIDView
from flask_login import login_user
from urllib.parse import quote
from flask_appbuilder.views import expose
from flask import request, redirect
from flask_oidc_ext import OpenIDConnect
from oauth2client.client import OAuth2Credentials

logger = logging.getLogger(__name__)


class OIDCSecurityManager(SupersetSecurityManager):

    def __init__(self, appbuilder):
        super(OIDCSecurityManager, self).__init__(appbuilder)
        if self.auth_type == AUTH_OID:
            self.oid = OpenIDConnect(self.appbuilder.get_app)
        self.authoidview = AuthOIDCView

class AuthOIDCView(AuthOIDView):
    @expose('/login/', methods=['GET', 'POST'])
    def login(self, flag=True):
        sm = self.appbuilder.sm
        oidc = sm.oid
        superset_roles = ["Admin", "Alpha", "Gamma", "Public", "granter", "sql_lab"]
        default_role = "Gamma"

        @self.appbuilder.sm.oid.require_login
        def handle_login():
            user = sm.auth_user_oid(oidc.user_getfield('email'))

            if user is None:
                info = oidc.user_getinfo(
                    ['preferred_username', 'given_name', 'family_name', 'email', 'roles'])
                roles = [role for role in superset_roles if
                         role in info.get('roles', [])]
                roles += [default_role, ] if not roles else []
                user = sm.add_user(info.get('preferred_username'),
                                   info.get('given_name', ''),
                                   info.get('family_name', ''),
                                   info.get('email'),
                                   [sm.find_role(role) for role in roles])

            login_user(user, remember=False)
            return redirect(self.appbuilder.get_url_for_index)

        return handle_login()

    @expose('/logout/', methods=['GET', 'POST'])
    def logout(self):
        try:
            oidc = self.appbuilder.sm.oid
            info = oidc.user_getinfo(
                ['preferred_username', 'email', 'sub', 'given_name', 'iss'])
            id_token_jwt = OAuth2Credentials.from_json(
                oidc.credentials_store[info.get('sub')]).id_token_jwt
            oidc.logout()
            super(AuthOIDCView, self).logout()
            logoutUri = oidc.client_secrets.get('issuer') + '/protocol/openid-connect/logout'
            post_logout_redirect_uri = oidc.client_secrets.get('post_logout_redirect_uri')
            return redirect(logoutUri + '?id_token_hint=' + id_token_jwt + '&post_logout_redirect_uri=' + 
                        quote(post_logout_redirect_uri))
        except Exception as err:
            msg = repr(err)
            if msg.find("User was not authenticated") != -1:
                return redirect('/login/')
            raise

三、linux docker环境修改

上面介绍的内容是在本地直接运行,如果在docker中需要将superset_config.py文件合并到superset/config.py中,主要原因是环境变量问题。所以总体来说,superset_config.py文件没有用的。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。