feat: 添加x-api-key认证模式和downappuser角色自动分配
- 新增x_api_key_auth函数支持Anthropic标准x-api-key header认证 - get_apikey_user查询增加dappid字段 - 认证成功后自动创建并分配downappuser角色(id=dappid) - rbac/check_perm中增加x-api-key header检查,优先于Authorization
This commit is contained in:
parent
27794d3d25
commit
e142f4b84e
51
dapi/dapi.py
51
dapi/dapi.py
@ -33,24 +33,24 @@ async def get_secretkey(sor, appid):
|
|||||||
async def get_apikey_user(sor, apikey, client_ip):
|
async def get_apikey_user(sor, apikey, client_ip):
|
||||||
f = get_serverenv('password_encode')
|
f = get_serverenv('password_encode')
|
||||||
apikey = f(apikey)
|
apikey = f(apikey)
|
||||||
sql = """select u.*, b.allowedips from downapikey a, users u, downapp b
|
sql = """select u.*, a.dappid, b.allowedips from downapikey a, users u, downapp b
|
||||||
where a.userid = u.id
|
where a.userid = u.id
|
||||||
and b.id = a.dappid
|
and b.id = a.dappid
|
||||||
and apikey=${apikey}$
|
and a.apikey=${apikey}$
|
||||||
and expired_date > ${today}$"""
|
and a.expires_at > ${today}$"""
|
||||||
|
|
||||||
recs = await sor.sqlExe(sql, {"apikey":apikey, 'today': curDateString()})
|
recs = await sor.sqlExe(sql, {"apikey":apikey, 'today': curDateString()})
|
||||||
if len(recs) < 1:
|
if len(recs) < 1:
|
||||||
debug(f'{apikey=} not registered')
|
debug(f'{apikey=} not registered')
|
||||||
return None
|
return None
|
||||||
rec = recs[0]
|
rec = recs[0]
|
||||||
if rec.allowips is None:
|
if rec.allowedips is None:
|
||||||
return rec
|
return rec
|
||||||
|
|
||||||
ips = rec.allowedips.split(',')
|
ips = rec.allowedips.split(',')
|
||||||
ips = [ ip.strip() for ip in ips ]
|
ips = [ ip.strip() for ip in ips ]
|
||||||
if client_ip not in ips:
|
if client_ip not in ips:
|
||||||
debug(f' {client_ip} not in {rec.allowips=}')
|
debug(f' {client_ip} not in {rec.allowedips=}')
|
||||||
return None
|
return None
|
||||||
return rec
|
return rec
|
||||||
|
|
||||||
@ -75,8 +75,49 @@ async def apikey_user(sor, apikey, client_ip, request):
|
|||||||
debug(f'get_apikey_user() {apikey=}, {client_ip} return None')
|
debug(f'get_apikey_user() {apikey=}, {client_ip} return None')
|
||||||
return None
|
return None
|
||||||
await user_login(request, user.id, username=user.username, userorgid=user.orgid)
|
await user_login(request, user.id, username=user.username, userorgid=user.orgid)
|
||||||
|
|
||||||
|
# 认证成功后,给用户添加downappuser角色(角色id=downapp.id)
|
||||||
|
dappid = getattr(user, 'dappid', None)
|
||||||
|
if dappid:
|
||||||
|
await ensure_downappuser_role_and_assign(sor, user.id, dappid)
|
||||||
|
|
||||||
return user.id
|
return user.id
|
||||||
|
|
||||||
|
async def ensure_downappuser_role_and_assign(sor, userid, dappid):
|
||||||
|
"""确保downappuser角色存在(id=dappid),并分配给用户"""
|
||||||
|
try:
|
||||||
|
# 检查角色是否存在,不存在则创建
|
||||||
|
roles = await sor.R('role', {'id': dappid})
|
||||||
|
if not roles:
|
||||||
|
await sor.C('role', {
|
||||||
|
'id': dappid,
|
||||||
|
'name': 'downappuser',
|
||||||
|
'orgtypeid': '*'
|
||||||
|
})
|
||||||
|
debug(f'created downappuser role: {dappid}')
|
||||||
|
|
||||||
|
# 检查用户是否已有该角色
|
||||||
|
existing = await sor.R('userrole', {'userid': userid, 'roleid': dappid})
|
||||||
|
if not existing:
|
||||||
|
from appPublic.uniqueID import getID
|
||||||
|
await sor.C('userrole', {
|
||||||
|
'id': getID(),
|
||||||
|
'userid': userid,
|
||||||
|
'roleid': dappid
|
||||||
|
})
|
||||||
|
debug(f'assigned downappuser role {dappid} to user {userid}')
|
||||||
|
except Exception as e:
|
||||||
|
exception(f'ensure_downappuser_role_and_assign error: {e}')
|
||||||
|
|
||||||
|
async def x_api_key_auth(sor, request):
|
||||||
|
"""Anthropic标准认证模式:从 x-api-key header 读取apikey"""
|
||||||
|
apikey = request.headers.get('x-api-key')
|
||||||
|
if apikey is None:
|
||||||
|
debug(f'x-api-key header not found')
|
||||||
|
return None
|
||||||
|
client_ip = request['client_ip']
|
||||||
|
return await apikey_user(sor, apikey, client_ip, request)
|
||||||
|
|
||||||
async def deerer_auth(sor, request):
|
async def deerer_auth(sor, request):
|
||||||
auth = request.headers.get('Authorization')
|
auth = request.headers.get('Authorization')
|
||||||
if auth is None:
|
if auth is None:
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
from dapi.dapi import sync_user, bearer_auth, deerer_auth, deerer_user, apikey_user, create_user_apikey
|
from dapi.dapi import sync_user, bearer_auth, deerer_auth, deerer_user, apikey_user, create_user_apikey, x_api_key_auth
|
||||||
from ahserver.serverenv import ServerEnv
|
from ahserver.serverenv import ServerEnv
|
||||||
from rbac.check_perm import register_auth_method
|
from rbac.check_perm import register_auth_method
|
||||||
|
|
||||||
@ -8,6 +8,7 @@ def load_dapi():
|
|||||||
env.deerer_user = deerer_user
|
env.deerer_user = deerer_user
|
||||||
env.apikey_user = apikey_user
|
env.apikey_user = apikey_user
|
||||||
env.create_user_apikey = create_user_apikey
|
env.create_user_apikey = create_user_apikey
|
||||||
|
env.x_api_key_auth = x_api_key_auth
|
||||||
register_auth_method('Bearer ', bearer_auth)
|
register_auth_method('Bearer ', bearer_auth)
|
||||||
register_auth_method('Deerer ', deerer_auth)
|
register_auth_method('Deerer ', deerer_auth)
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user