feat: add callback handler and group query API for client auth flow
- Add rl_handle_callback() to init.py: handles Volcengine H5 auth callback, queries vendor for result, registers rl_org_group mapping - Add rl_query_groups() to init.py: client API to query authenticated group_ids for an org - Add wwwroot/api/rl_callback.dspy endpoint (no auth required for vendor POST) - Add wwwroot/api/rl_query_groups.dspy endpoint (login required) - Remove deprecated rl_app_user_* files (no longer used) - Update scripts/load_path.py: rl_callback -> any role, rl_query_groups -> logined
This commit is contained in:
parent
3ad9b2bb46
commit
af65c307f8
@ -643,6 +643,126 @@ async def rl_sync_asset_status_user(org_id, asset_id, downapp_id):
|
||||
return {"success": True, "status": status, "url": url}
|
||||
|
||||
|
||||
async def rl_handle_callback(byted_token, project_name="default"):
|
||||
"""
|
||||
Callback handler: Volcengine POSTs here after H5 auth completes.
|
||||
Looks up local group by byted_token, queries vendor for result,
|
||||
then registers rl_org_group mapping.
|
||||
"""
|
||||
dbname = _get_dbname()
|
||||
db = DBPools()
|
||||
|
||||
# 1. Find local group by byted_token
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
recs = await sor.R("rl_asset_group", {"byted_token": byted_token})
|
||||
if not recs:
|
||||
return {"success": False, "message": "未找到对应的认证会话"}
|
||||
rec = recs[0]
|
||||
local_group_id = rec.id
|
||||
org_id = rec.org_id
|
||||
|
||||
# Already processed?
|
||||
if rec.status == "active" and rec.vendor_group_id:
|
||||
debug(f"callback already processed for group {local_group_id}")
|
||||
return {
|
||||
"success": True,
|
||||
"local_group_id": local_group_id,
|
||||
"vendor_group_id": rec.vendor_group_id,
|
||||
"message": "已处理",
|
||||
}
|
||||
|
||||
# 2. Get vendor keys
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
vrecs = await sor.R("rl_vendor_config", {"vendor": "volcengine"})
|
||||
if not vrecs:
|
||||
return {"success": False, "message": "供应商配置不存在"}
|
||||
vrec = vrecs[0]
|
||||
if vrec.status != "active":
|
||||
return {"success": False, "message": "供应商服务已停用"}
|
||||
env = ServerEnv()
|
||||
ak = env.password_decode(vrec.ak)
|
||||
sk = env.password_decode(vrec.sk)
|
||||
|
||||
# 3. Query vendor for result
|
||||
client = _get_client("volcengine", ak, sk)
|
||||
result = client.get_visual_validate_result(byted_token, project_name)
|
||||
|
||||
if "error" in result:
|
||||
error(f"callback query vendor error: {result}")
|
||||
return {"success": False, "message": result.get("error", "查询失败")}
|
||||
|
||||
vendor_group_id = result.get("GroupId", "")
|
||||
if not vendor_group_id:
|
||||
return {"success": False, "message": "尚未完成认证或认证失败"}
|
||||
|
||||
# 4. Register rl_org_group mapping
|
||||
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
mapping_id = getID()
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
existing = await sor.R("rl_org_group", {
|
||||
"org_id": org_id,
|
||||
"vendor": "volcengine",
|
||||
})
|
||||
if existing:
|
||||
await sor.U("rl_org_group", {
|
||||
"vendor_group_id": vendor_group_id,
|
||||
"local_group_id": local_group_id,
|
||||
"update_time": now,
|
||||
}, {"id": existing[0].id})
|
||||
else:
|
||||
await sor.I("rl_org_group", {
|
||||
"id": mapping_id,
|
||||
"org_id": org_id,
|
||||
"vendor": "volcengine",
|
||||
"vendor_group_id": vendor_group_id,
|
||||
"local_group_id": local_group_id,
|
||||
"status": "active",
|
||||
"create_time": now,
|
||||
})
|
||||
|
||||
# 5. Update rl_asset_group status
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
await sor.U("rl_asset_group", {
|
||||
"vendor_group_id": vendor_group_id,
|
||||
"status": "active",
|
||||
"update_time": now,
|
||||
}, {"id": local_group_id})
|
||||
|
||||
debug(f"callback processed: org={org_id}, group={local_group_id}, "
|
||||
f"vendor_group={vendor_group_id}")
|
||||
return {
|
||||
"success": True,
|
||||
"local_group_id": local_group_id,
|
||||
"vendor_group_id": vendor_group_id,
|
||||
}
|
||||
|
||||
|
||||
async def rl_query_groups(org_id):
|
||||
"""
|
||||
Client API: Query authenticated group_ids for an org.
|
||||
Returns list of (local_group_id, vendor_group_id, status) mappings.
|
||||
"""
|
||||
dbname = _get_dbname()
|
||||
db = DBPools()
|
||||
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
recs = await sor.R("rl_org_group", {"org_id": org_id})
|
||||
if not recs:
|
||||
return {"success": True, "groups": []}
|
||||
|
||||
groups = []
|
||||
for r in recs:
|
||||
groups.append({
|
||||
"local_group_id": r.local_group_id,
|
||||
"vendor_group_id": r.vendor_group_id,
|
||||
"vendor": r.vendor,
|
||||
"status": r.status,
|
||||
"create_time": getattr(r, "create_time", ""),
|
||||
})
|
||||
|
||||
return {"success": True, "groups": groups}
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Module loader
|
||||
# ============================================================
|
||||
@ -664,5 +784,7 @@ def load_reallife_asset():
|
||||
g.rl_check_validate_and_map = rl_check_validate_and_map
|
||||
g.rl_upload_user = rl_upload_user
|
||||
g.rl_sync_asset_status_user = rl_sync_asset_status_user
|
||||
g.rl_handle_callback = rl_handle_callback
|
||||
g.rl_query_groups = rl_query_groups
|
||||
|
||||
return True
|
||||
|
||||
@ -21,7 +21,9 @@ python = os.path.join(sage_root, "py3/bin/python")
|
||||
set_perm = os.path.join(sage_root, "set_role_perm.py")
|
||||
|
||||
# Permission definitions
|
||||
paths_any = [] # No login required
|
||||
paths_any = [
|
||||
"/reallife_asset/api/rl_callback.dspy", # Volcengine callback - no auth
|
||||
]
|
||||
paths_logined = [
|
||||
"/reallife_asset",
|
||||
"/reallife_asset/index.ui",
|
||||
@ -50,12 +52,7 @@ paths_logined = [
|
||||
"/reallife_asset/api/rl_verify.dspy",
|
||||
"/reallife_asset/api/rl_upload.dspy",
|
||||
"/reallife_asset/api/rl_status.dspy",
|
||||
# Ops management CRUD
|
||||
"/reallife_asset/api/rl_app_user_create.dspy",
|
||||
"/reallife_asset/api/rl_app_user_update.dspy",
|
||||
"/reallife_asset/api/rl_app_user_delete.dspy",
|
||||
"/reallife_asset/rl_app_user_list",
|
||||
"/reallife_asset/rl_app_user_list/index.ui",
|
||||
"/reallife_asset/api/rl_query_groups.dspy",
|
||||
# Vendor Config CRUD
|
||||
"/reallife_asset/api/rl_vendor_config_create.dspy",
|
||||
"/reallife_asset/api/rl_vendor_config_update.dspy",
|
||||
|
||||
@ -1,32 +0,0 @@
|
||||
# Create app record
|
||||
org_id = params_kw.get('org_id', (await get_userorgid()) or '0')
|
||||
id = params_kw.get('id', getID())
|
||||
now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
# Decrypt keys if provided by form? No, usually Ops enters plain text, we encrypt.
|
||||
ak = params_kw.get('ak', '')
|
||||
sk = params_kw.get('sk', '')
|
||||
env = ServerEnv()
|
||||
if ak: ak = env.password_encode(ak)
|
||||
if sk: sk = env.password_encode(sk)
|
||||
|
||||
data = {
|
||||
"id": id,
|
||||
"org_id": org_id,
|
||||
"downapp_id": params_kw.get('downapp_id', ''),
|
||||
"vendor": params_kw.get('vendor', 'volcengine'),
|
||||
"status": params_kw.get('status', 'pending'),
|
||||
"ak": ak,
|
||||
"sk": sk,
|
||||
"callback_url": params_kw.get('callback_url', ''),
|
||||
"remark": params_kw.get('remark', ''),
|
||||
"create_time": now,
|
||||
"update_time": now
|
||||
}
|
||||
|
||||
db = DBPools()
|
||||
dbname = get_module_dbname('reallife_asset')
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
await sor.I("rl_app_user", data)
|
||||
|
||||
return {"success": True, "id": id}
|
||||
@ -1,9 +0,0 @@
|
||||
id = params_kw.get('id', '')
|
||||
if not id: return {"success": False, "message": "id required"}
|
||||
|
||||
db = DBPools()
|
||||
dbname = get_module_dbname('reallife_asset')
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
await sor.D("rl_app_user", {"id": id})
|
||||
|
||||
return {"success": True}
|
||||
@ -1,31 +0,0 @@
|
||||
id = params_kw.get('id', '')
|
||||
if not id: return {"success": False, "message": "id required"}
|
||||
|
||||
db = DBPools()
|
||||
dbname = get_module_dbname('reallife_asset')
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
recs = await sor.R("rl_app_user", {"id": id})
|
||||
if not recs: return {"success": False, "message": "Not found"}
|
||||
|
||||
# Prepare update data
|
||||
upd = {}
|
||||
for k in ['status', 'remark', 'callback_url', 'vendor']:
|
||||
if params_kw.get(k):
|
||||
upd[k] = params_kw.get(k)
|
||||
|
||||
# Handle keys encryption
|
||||
ak = params_kw.get('ak', None)
|
||||
sk = params_kw.get('sk', None)
|
||||
if ak is not None:
|
||||
env = ServerEnv()
|
||||
upd['ak'] = env.password_encode(ak)
|
||||
if sk is not None:
|
||||
env = ServerEnv()
|
||||
upd['sk'] = env.password_encode(sk)
|
||||
|
||||
upd['update_time'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
async with db.sqlorContext(dbname) as sor:
|
||||
await sor.U("rl_app_user", upd, {"id": id})
|
||||
|
||||
return {"success": True}
|
||||
31
wwwroot/api/rl_callback.dspy
Normal file
31
wwwroot/api/rl_callback.dspy
Normal file
@ -0,0 +1,31 @@
|
||||
import json
|
||||
|
||||
# Volcengine callback POSTs JSON body with BytedToken and result info.
|
||||
# The callback URL is configured when calling CreateVisualValidateSession.
|
||||
# Typical payload: {"BytedToken": "...", "ReqUUID": "...", "Status": "..."}
|
||||
|
||||
# Try to parse JSON body first
|
||||
body_str = http_request.get("body", "") or ""
|
||||
byted_token = ""
|
||||
project_name = "default"
|
||||
|
||||
try:
|
||||
body = json.loads(body_str) if body_str else {}
|
||||
byted_token = body.get("BytedToken", "")
|
||||
# Also check alternative field names
|
||||
if not byted_token:
|
||||
byted_token = body.get("byted_token", "")
|
||||
if not byted_token:
|
||||
byted_token = body.get("Token", "")
|
||||
except:
|
||||
byted_token = ""
|
||||
|
||||
# Fallback: check query params
|
||||
if not byted_token:
|
||||
byted_token = params_kw.get("BytedToken", params_kw.get("byted_token", ""))
|
||||
|
||||
if not byted_token:
|
||||
return {"success": False, "message": "缺少 BytedToken 参数"}
|
||||
|
||||
result = await rl_handle_callback(byted_token, project_name)
|
||||
return result
|
||||
4
wwwroot/api/rl_query_groups.dspy
Normal file
4
wwwroot/api/rl_query_groups.dspy
Normal file
@ -0,0 +1,4 @@
|
||||
org_id = (await get_userorgid()) or '0'
|
||||
|
||||
result = await rl_query_groups(org_id)
|
||||
return result
|
||||
Loading…
x
Reference in New Issue
Block a user