first commit
This commit is contained in:
commit
c6d775cd7c
28
README.md
Normal file
28
README.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# 第三方应用登录服务器端
|
||||||
|
|
||||||
|
本模块为应用软件提供其他第三方应用的客户使用apikey自动登录
|
||||||
|
|
||||||
|
## 依赖的软件包
|
||||||
|
* [ahserver](https://git.kaiyuancloud.cn/yumoqing/ahserver)
|
||||||
|
* [sqlor](https://git.kaiyuancloud.cn/yumoqing/sqlor)
|
||||||
|
* [apppublic](https://git.kaiyuancloud.cn/yumoqing/apppublic)
|
||||||
|
|
||||||
|
## 安装
|
||||||
|
|
||||||
|
pip install kyapikeyserver
|
||||||
|
|
||||||
|
## 业务流程
|
||||||
|
|
||||||
|
* 申请系统下位的apikey
|
||||||
|
|
||||||
|
客户注册后,添加一个下位系统,并将系统自动生成的apikey和secretkey复制到实际的下午系统中,登记
|
||||||
|
|
||||||
|
* 用户同步
|
||||||
|
|
||||||
|
下位系统:用上位系统生成的系统ak,sk将需要同步的用户(支持多个)按照用户同步的格式上传到本地系统
|
||||||
|
|
||||||
|
上位系统:系统收到请求后,添加系统本身的机构和用户,并为此用户生成apikey,与下位系统的userid一起返回给下位系统
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
3
json/build.sh
Executable file
3
json/build.sh
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
xls2ui -m ../models -o ../wwwroot kyapikey *.json
|
176
kyapikeyserver/server.py
Normal file
176
kyapikeyserver/server.py
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
from traceback import format_exc
|
||||||
|
from appPublic.log import debug, exception, info
|
||||||
|
from appPublic.timeUtils import curDateString
|
||||||
|
from uniqueID import getID
|
||||||
|
from time import time
|
||||||
|
from ahserver.serverenv import ServerEnv
|
||||||
|
from ahserver.auth_api import get_session_userinfo
|
||||||
|
from sqlor.dbpools import DBPools
|
||||||
|
form rbac.check_perm improt create_org, create_user
|
||||||
|
|
||||||
|
from appPublic.aes import aes_encrypt_ecb, aes_decrypt_ecb
|
||||||
|
|
||||||
|
return_messages = {
|
||||||
|
-9: '用户同步:未知未知错误',
|
||||||
|
-4: '用户同步:添加用户apikey失败',
|
||||||
|
-3: '用户同步:添加用户失败',
|
||||||
|
-2: '用户同步:添加机构失败',
|
||||||
|
-1: '用户同步:用户已同步'
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_dbname():
|
||||||
|
dbname = get_serverenv('get_module_dbname')('dapi')
|
||||||
|
return dbname
|
||||||
|
|
||||||
|
async def get_secretkey(sor, appid):
|
||||||
|
recs = await sor.R('kydownapp', {'id':appid})
|
||||||
|
if len(recs) < 1:
|
||||||
|
return None
|
||||||
|
secret_key = recs[0].secret_key
|
||||||
|
f = get_serverenv('password_decode')
|
||||||
|
return f(secret_key).encode('utf-8')
|
||||||
|
|
||||||
|
async def get_apikey_user(sor, apikey):
|
||||||
|
f = get_serverenv('password_encode')
|
||||||
|
apikey = f(apikey)
|
||||||
|
users = await sor.R('kydownapikey', {'apikey': apikey})
|
||||||
|
if len(users) < 1:
|
||||||
|
return None
|
||||||
|
apiuser = users[0]
|
||||||
|
if not apiuser.enabled:
|
||||||
|
e = Exception(f'user(id={apiuser.userid}) is not enabled')
|
||||||
|
exception(f'{e},{format_exc()}')
|
||||||
|
raise e
|
||||||
|
if apiuser.expires_at < curDateString():
|
||||||
|
e = Exception(f"user(id={apiuser.userid})'s apikey is expired({apiuser.expires_at})')
|
||||||
|
exception(f'{e}, {format_exc()}')
|
||||||
|
raise e
|
||||||
|
users = await sor.R('users', {'id': apiuser.userid, 'orgid': apiuser.orgid})
|
||||||
|
if len(users) < 1:
|
||||||
|
e = Exception(f'user(id={apiuser.userid}) not found in users')
|
||||||
|
exception(f'{e}, {format_exc()}')
|
||||||
|
raise e
|
||||||
|
return users[0]
|
||||||
|
|
||||||
|
async def get_user_from_bear_data(self, bear_data):
|
||||||
|
if not bear_data[:5] == 'Bear ':
|
||||||
|
return None
|
||||||
|
bear_data = bear_data[5:]
|
||||||
|
appid, cyber = bear_data.split('-:-')
|
||||||
|
db = DBPools()
|
||||||
|
dbname = get_dbname()
|
||||||
|
async with db.sqlorContext(dbname) as sor:
|
||||||
|
secretkey = await get_secretkey(sor, appid)
|
||||||
|
txt = aes_decrypt_ecb(secretkey, cyber)
|
||||||
|
t, apikey = txt.split(':')
|
||||||
|
userinfo = await get_apikey_user(apikey)
|
||||||
|
return userinfo
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def return_error(code):
|
||||||
|
return {
|
||||||
|
'status':'error',
|
||||||
|
'errcode': code,
|
||||||
|
'errmsg': return_messages.get(code, '未定义信息')
|
||||||
|
}
|
||||||
|
|
||||||
|
def return_success(data):
|
||||||
|
return {
|
||||||
|
'status':'success',
|
||||||
|
'data':data
|
||||||
|
}
|
||||||
|
|
||||||
|
async def get_orgid_by_dorgid(sor, dappid, dorgid):
|
||||||
|
d = {
|
||||||
|
'dappid':dappid,
|
||||||
|
'dorgid':dorgid
|
||||||
|
}
|
||||||
|
recs = await sor.R('kydownapikey', d)
|
||||||
|
if len(recs) < 1:
|
||||||
|
return None
|
||||||
|
return recs[0].orgid
|
||||||
|
|
||||||
|
async def check_duserid_exists(sor, dappid, dorgid, duserid):
|
||||||
|
d = {
|
||||||
|
'dappid': dappid,
|
||||||
|
'duserid': duserid,
|
||||||
|
'dorgid': dorgid
|
||||||
|
}
|
||||||
|
recs = await sor.R('kwdownapikey', d)
|
||||||
|
if len(recs):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def add_organzation(sor, dappid, org):
|
||||||
|
id = getID()
|
||||||
|
org['id'] = id
|
||||||
|
await create_org(sor, org)
|
||||||
|
return id
|
||||||
|
|
||||||
|
async def add_user(sor, user):
|
||||||
|
id = getID()
|
||||||
|
user['id'] = id
|
||||||
|
await create_user(sor, user, roles=user['roles']
|
||||||
|
return id
|
||||||
|
|
||||||
|
async def add_apikey(sor, dappid, dorgid, duserid, orgid, userid):
|
||||||
|
apikey = getID()
|
||||||
|
d = {
|
||||||
|
'id': getID,
|
||||||
|
'dappid': dappid,
|
||||||
|
'dorgid': dorgid,
|
||||||
|
'duserid': duserid,
|
||||||
|
'orgid': orgid,
|
||||||
|
'userid': userid,
|
||||||
|
'apikey': id,
|
||||||
|
'enabled': '1',
|
||||||
|
'created_at': curDateString(),
|
||||||
|
'expires_at': '9999-12-31'
|
||||||
|
}
|
||||||
|
await sor.C('kydownapikey', d)
|
||||||
|
return apikey
|
||||||
|
|
||||||
|
async def sync_user(request, params_kw, *args, **kw):
|
||||||
|
dappid = params_kw.dappid
|
||||||
|
db = DBPools()
|
||||||
|
dbname = get_dbname()
|
||||||
|
userinfo = await get_session_userinfo(request)
|
||||||
|
async with db.sqlorContext(dbname) as sor:
|
||||||
|
ret_users = []
|
||||||
|
roles = [{
|
||||||
|
'orgtypeid': 'customer',
|
||||||
|
'roles': [ 'customer', 'syncuser' ]
|
||||||
|
}]
|
||||||
|
for o in params_kw.organizations:
|
||||||
|
for u in o['users']:
|
||||||
|
dorgid = o['id']
|
||||||
|
duserid = u['id']
|
||||||
|
orgid = await get_orgid_by_dorgid(sor, dappid, dorgid)
|
||||||
|
if orgid is None:
|
||||||
|
if o.get('parentid') is None:
|
||||||
|
o['parentid'] = userinfo.userorgid
|
||||||
|
else:
|
||||||
|
nparentid = await get_orgid_by_dorgid(sor, dappid, o.get('parentid'))
|
||||||
|
o['parentid'] = nparentid
|
||||||
|
orgid = await add_organzation(sor, dappid, o)
|
||||||
|
if orgid is None:
|
||||||
|
return return_error(-2)
|
||||||
|
u['orgid'] = o['id']
|
||||||
|
u['roles'] = roles
|
||||||
|
exists = check_duserid_exists(sor, dappid, dorgid, duserid)
|
||||||
|
if exists:
|
||||||
|
return return_error(-1)
|
||||||
|
userid = await add_user(sor, u)
|
||||||
|
if userid is None:
|
||||||
|
return return_error(-3)
|
||||||
|
apikey = await add_apikey(sor, dappid, orgid, userid, u)
|
||||||
|
if apikey is None:
|
||||||
|
return return_error(-4)
|
||||||
|
ret_users.append({
|
||||||
|
'id': u['id'],
|
||||||
|
'apikey': apikey
|
||||||
|
})
|
||||||
|
return return_success(ret_users)
|
||||||
|
return return_error(-9)
|
||||||
|
|
BIN
models/kydownapikey.xlsx
Normal file
BIN
models/kydownapikey.xlsx
Normal file
Binary file not shown.
BIN
models/kydownapp.xlsx
Normal file
BIN
models/kydownapp.xlsx
Normal file
Binary file not shown.
4
pyproject.toml
Normal file
4
pyproject.toml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["setuptools>=61", "wheel"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
34
setup.cfg
Normal file
34
setup.cfg
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[metadata]
|
||||||
|
name=appPublic
|
||||||
|
version = 5.2.3
|
||||||
|
description = Your project description
|
||||||
|
authors = [{
|
||||||
|
author = "yu moqing"
|
||||||
|
author_email = "yumoqing@gmail.com" }]
|
||||||
|
readme = "README.md"
|
||||||
|
license = "MIT"
|
||||||
|
[options]
|
||||||
|
packages = find:
|
||||||
|
requires-python = ">=3.8"
|
||||||
|
install_requires =
|
||||||
|
xlrd
|
||||||
|
bs4
|
||||||
|
xlwt
|
||||||
|
nanoid
|
||||||
|
psutil
|
||||||
|
ujson
|
||||||
|
numpy
|
||||||
|
rsa
|
||||||
|
brotli
|
||||||
|
aiohttp
|
||||||
|
asyncio
|
||||||
|
aiohttp
|
||||||
|
aiohttp_socks
|
||||||
|
requests
|
||||||
|
jinja2
|
||||||
|
pyzmq
|
||||||
|
cryptography
|
||||||
|
bcrypt
|
||||||
|
asyncssh
|
||||||
|
eventpy
|
||||||
|
|
Loading…
Reference in New Issue
Block a user