以编程方式创建用户
Creating a user programmatically
如何在 Superset 中以编程方式创建具有已定义角色的用户?
假设我有一个电子邮件登录页面。用户注册。注册后,我想以编程方式将具有 gamma 角色的用户创建到 Superset 实例中。
如果您打算以编程方式创建用户,那么您最好的选择可能是考虑覆盖底层 Flask-App-Builder (F.A.B.) 框架的 SecurityManager - Superset 基于.
可在此处找到文档:https://github.com/dpgaspar/Flask-AppBuilder/blob/master/docs/security.rst#your-custom-security
话虽如此 - 感觉您的问题实际上是关于如何允许用户在 Superset 中自行注册并默认为他们提供 Gamma 角色。
这是一个明确的 FAB 地址用例,您应该能够通过配置实现这一点:http://flask-appbuilder.readthedocs.io/en/latest/user_registration.html
我使用 a reply from superset git 并创建了以下 类 来添加具有角色的用户。
您需要一个包含用户信息和您要应用的角色名称的 json 文件。像这样:
[
{
"first_name": "a",
"last_name": "b",
"username": "abc",
"email": "abc@def.com",
"password": "123",
"roles": ["generalViewer","databaseXView"]
},
{
"first_name": "b",
"last_name": "c",
"username": "bcd",
"email": "bcd@def.com",
"password": "123",
"roles": ["generalViewer","databaseXView"]
}
]
因为我们需要使用角色名称(我们可以通过正常导航从超集中获取它们)来设置数据库凭据以获取 role_id。还需要设置任何有权创建另一个用户的登录。
import requests
import json
from bs4 import BeautifulSoup as bs
from bs4 import Comment
from time import sleep
import psycopg2
from typing import List, Tuple
import pandas as pd
class SupersetApi:
def __init__(self, username=None, password=None):
self.s = requests.session()
self.base_url = "http://123.45.67.890:8088/" #superset server ip
self._csrf = self._getCSRF(self.url('login/'))
self.headers = {'X-CSRFToken': self._csrf, 'Referer': self.url('login/')}
# note: does not use headers because of flask_wtf.csrf.validate_csrf
# if data is dict it is used as form and ends up empty but flask_wtf checks if data ...
payload = {'username': username, 'password': password, 'csrf_token': self._csrf}
self.post('login/', payload, None)
#self.s.post(self.url(), data=payload, headers = {})
def url(self, url_path):
return self.base_url + url_path
def get(self, url_path):
return self.s.get(self.url(url_path), headers=self.headers)
def post(self, url_path, data=None, json_data=None, **kwargs):
kwargs.update({'url': self.url(url_path), 'headers': self.headers})
if data:
data['csrf_token'] = self._csrf
kwargs['data'] = data
if json_data:
kwargs['json'] = json_data
try:
response = self.s.post(**kwargs)
statusCode = response.status_code
if statusCode < 399:
return True, statusCode
else:
print('POST response: {}'.format(statusCode))
return False, statusCode
except Exception as e:
print(e)
return False, e
def _getCSRF(self, url_path):
try:
response = self.s.get(url_path)
response.raise_for_status()
except Exception as e:
print(e)
exit()
soup = bs(response.content, "html.parser")
for tag in soup.find_all('input', id='csrf_token'):
csrf_token = tag['value']
return csrf_token
class PostgresDB:
def __init__(self, db_name: str, db_user: str, db_host: str, db_password: str) -> None:
self.db_name = db_name
self.db_user = db_user
self.db_host = db_host
self.db_password = db_password
self.conn = None
self.cur = None
def connect(self) -> None:
try:
self.conn = psycopg2.connect('dbname={} user={} host={} password={}'.format(
self.db_name, self.db_user, self.db_host, self.db_password))
self.cur = self.conn.cursor()
except Exception as e:
raise Exception('Couldn\'t connect to the database. Error: {}'.format(e))
def commit(self) -> None:
if self.conn is not None:
self.conn.commit()
else:
raise Exception('Connection not opened to commit')
def close_connection(self) -> None:
if self.cur is not None or self.conn is not None:
try:
self.cur.close()
except:
pass
try:
self.conn.close()
except:
pass
else:
print('Connection and Cursor not opened to be closed')
def get_from_ab_role(self, columns: List, filters: str) -> List:
roles_table = 'public.ab_role'
sql_columns = ','.join(columns)
sql = "SELECT {} FROM {} WHERE {}".format(sql_columns, roles_table, filters)
self.cur.execute(sql)
return self.cur.fetchall()
class SupersetUser:
def __init__(self, user_dict: dict, db: 'PostgresDB'):
self.first_name = user_dict.get('first_name')
self.last_name = user_dict.get('last_name')
self.username = user_dict.get('username')
self.email = user_dict.get('email')
self.active = True
self.password = user_dict.get('password')
self.roles = self.get_role_id(db, user_dict.get('roles'))
def get_role_id(self, db: 'PostgresDB', roles: List):
filter = 'name = '
filter = filter + "'{}' ".format(roles[0])
if len(roles) > 1:
for role in roles[1:]:
filter = filter + "OR name = '{}' ".format(role)
ids = []
for id in db.get_from_ab_role(['id'], filter):
ids.append(str(id[0]))
return ids
def create_user(self, superset_api: SupersetApi) -> Tuple:
Error_friendly_message = None
Error_not = True
url_path = 'users/api/create'
payload = {'first_name': self.first_name,
'last_name': self.last_name,
'username': self.username,
'email': self.email,
'active': self.active,
'conf_password': self.password,
'password': self.password,
'roles': self.roles
}
Error_not, http_response_code = superset_api.post(url_path=url_path, json=payload)
if Error_not:
print('User {} created. Corresponding e-mail: {}'.format(self.username, self.email))
return Error_not, Error_friendly_message, http_response_code
elif http_response_code == 500:
Error_not = False
Error_friendly_message = ('Ops! Something went wrong. Probably already exist an '
'user with the same e-mail: {}, or an error with the json variables... '
'All of them must be strings or a list of strings'.format(self.email))
return Error_not, Error_friendly_message, http_response_code
else:
Error_not = False
Error_friendly_message = 'Ops! Something went wrong. Try again.'
return Error_not, Error_friendly_message, http_response_code
#file that contains the users to be created
FILE_NAME = 'users.json'
#need credentials from user with admin role to create new user
ADMIN_USR = 'admin'
ADMIN_PSWD = 'adminpassword'
DB_NAME = 'superset_database'
DB_USER = 'superset_user'
DB_HOST = '123.45.67.890'
DB_PSWD = 'superset_password'
superset = SupersetApi(ADMIN_USR, ADMIN_PSWD)
portgre_db = PostgresDB(DB_NAME, DB_USER, DB_HOST, DB_PSWD)
portgre_db.connect()
try:
with open(FILE_NAME, 'r') as f:
users = json.load(f)
print('File successfully read')
except FileNotFoundError as e:
print(e)
for index, user in enumerate(users):
userRoles = []
superset_user = SupersetUser(user, portgre_db)
Error_not, Error_friendly_message, http_response_code = superset_user.create_user(superset)
if not Error_not:
print('Could\'t create user {}.'.format(superset_user.username))
print(Error_friendly_message)
print('HTTP Response Code: {}'.format(http_response_code))
portgre_db.close_connection()
如何在 Superset 中以编程方式创建具有已定义角色的用户?
假设我有一个电子邮件登录页面。用户注册。注册后,我想以编程方式将具有 gamma 角色的用户创建到 Superset 实例中。
如果您打算以编程方式创建用户,那么您最好的选择可能是考虑覆盖底层 Flask-App-Builder (F.A.B.) 框架的 SecurityManager - Superset 基于.
可在此处找到文档:https://github.com/dpgaspar/Flask-AppBuilder/blob/master/docs/security.rst#your-custom-security
话虽如此 - 感觉您的问题实际上是关于如何允许用户在 Superset 中自行注册并默认为他们提供 Gamma 角色。
这是一个明确的 FAB 地址用例,您应该能够通过配置实现这一点:http://flask-appbuilder.readthedocs.io/en/latest/user_registration.html
我使用 a reply from superset git 并创建了以下 类 来添加具有角色的用户。 您需要一个包含用户信息和您要应用的角色名称的 json 文件。像这样:
[
{
"first_name": "a",
"last_name": "b",
"username": "abc",
"email": "abc@def.com",
"password": "123",
"roles": ["generalViewer","databaseXView"]
},
{
"first_name": "b",
"last_name": "c",
"username": "bcd",
"email": "bcd@def.com",
"password": "123",
"roles": ["generalViewer","databaseXView"]
}
]
因为我们需要使用角色名称(我们可以通过正常导航从超集中获取它们)来设置数据库凭据以获取 role_id。还需要设置任何有权创建另一个用户的登录。
import requests
import json
from bs4 import BeautifulSoup as bs
from bs4 import Comment
from time import sleep
import psycopg2
from typing import List, Tuple
import pandas as pd
class SupersetApi:
def __init__(self, username=None, password=None):
self.s = requests.session()
self.base_url = "http://123.45.67.890:8088/" #superset server ip
self._csrf = self._getCSRF(self.url('login/'))
self.headers = {'X-CSRFToken': self._csrf, 'Referer': self.url('login/')}
# note: does not use headers because of flask_wtf.csrf.validate_csrf
# if data is dict it is used as form and ends up empty but flask_wtf checks if data ...
payload = {'username': username, 'password': password, 'csrf_token': self._csrf}
self.post('login/', payload, None)
#self.s.post(self.url(), data=payload, headers = {})
def url(self, url_path):
return self.base_url + url_path
def get(self, url_path):
return self.s.get(self.url(url_path), headers=self.headers)
def post(self, url_path, data=None, json_data=None, **kwargs):
kwargs.update({'url': self.url(url_path), 'headers': self.headers})
if data:
data['csrf_token'] = self._csrf
kwargs['data'] = data
if json_data:
kwargs['json'] = json_data
try:
response = self.s.post(**kwargs)
statusCode = response.status_code
if statusCode < 399:
return True, statusCode
else:
print('POST response: {}'.format(statusCode))
return False, statusCode
except Exception as e:
print(e)
return False, e
def _getCSRF(self, url_path):
try:
response = self.s.get(url_path)
response.raise_for_status()
except Exception as e:
print(e)
exit()
soup = bs(response.content, "html.parser")
for tag in soup.find_all('input', id='csrf_token'):
csrf_token = tag['value']
return csrf_token
class PostgresDB:
def __init__(self, db_name: str, db_user: str, db_host: str, db_password: str) -> None:
self.db_name = db_name
self.db_user = db_user
self.db_host = db_host
self.db_password = db_password
self.conn = None
self.cur = None
def connect(self) -> None:
try:
self.conn = psycopg2.connect('dbname={} user={} host={} password={}'.format(
self.db_name, self.db_user, self.db_host, self.db_password))
self.cur = self.conn.cursor()
except Exception as e:
raise Exception('Couldn\'t connect to the database. Error: {}'.format(e))
def commit(self) -> None:
if self.conn is not None:
self.conn.commit()
else:
raise Exception('Connection not opened to commit')
def close_connection(self) -> None:
if self.cur is not None or self.conn is not None:
try:
self.cur.close()
except:
pass
try:
self.conn.close()
except:
pass
else:
print('Connection and Cursor not opened to be closed')
def get_from_ab_role(self, columns: List, filters: str) -> List:
roles_table = 'public.ab_role'
sql_columns = ','.join(columns)
sql = "SELECT {} FROM {} WHERE {}".format(sql_columns, roles_table, filters)
self.cur.execute(sql)
return self.cur.fetchall()
class SupersetUser:
def __init__(self, user_dict: dict, db: 'PostgresDB'):
self.first_name = user_dict.get('first_name')
self.last_name = user_dict.get('last_name')
self.username = user_dict.get('username')
self.email = user_dict.get('email')
self.active = True
self.password = user_dict.get('password')
self.roles = self.get_role_id(db, user_dict.get('roles'))
def get_role_id(self, db: 'PostgresDB', roles: List):
filter = 'name = '
filter = filter + "'{}' ".format(roles[0])
if len(roles) > 1:
for role in roles[1:]:
filter = filter + "OR name = '{}' ".format(role)
ids = []
for id in db.get_from_ab_role(['id'], filter):
ids.append(str(id[0]))
return ids
def create_user(self, superset_api: SupersetApi) -> Tuple:
Error_friendly_message = None
Error_not = True
url_path = 'users/api/create'
payload = {'first_name': self.first_name,
'last_name': self.last_name,
'username': self.username,
'email': self.email,
'active': self.active,
'conf_password': self.password,
'password': self.password,
'roles': self.roles
}
Error_not, http_response_code = superset_api.post(url_path=url_path, json=payload)
if Error_not:
print('User {} created. Corresponding e-mail: {}'.format(self.username, self.email))
return Error_not, Error_friendly_message, http_response_code
elif http_response_code == 500:
Error_not = False
Error_friendly_message = ('Ops! Something went wrong. Probably already exist an '
'user with the same e-mail: {}, or an error with the json variables... '
'All of them must be strings or a list of strings'.format(self.email))
return Error_not, Error_friendly_message, http_response_code
else:
Error_not = False
Error_friendly_message = 'Ops! Something went wrong. Try again.'
return Error_not, Error_friendly_message, http_response_code
#file that contains the users to be created
FILE_NAME = 'users.json'
#need credentials from user with admin role to create new user
ADMIN_USR = 'admin'
ADMIN_PSWD = 'adminpassword'
DB_NAME = 'superset_database'
DB_USER = 'superset_user'
DB_HOST = '123.45.67.890'
DB_PSWD = 'superset_password'
superset = SupersetApi(ADMIN_USR, ADMIN_PSWD)
portgre_db = PostgresDB(DB_NAME, DB_USER, DB_HOST, DB_PSWD)
portgre_db.connect()
try:
with open(FILE_NAME, 'r') as f:
users = json.load(f)
print('File successfully read')
except FileNotFoundError as e:
print(e)
for index, user in enumerate(users):
userRoles = []
superset_user = SupersetUser(user, portgre_db)
Error_not, Error_friendly_message, http_response_code = superset_user.create_user(superset)
if not Error_not:
print('Could\'t create user {}.'.format(superset_user.username))
print(Error_friendly_message)
print('HTTP Response Code: {}'.format(http_response_code))
portgre_db.close_connection()