baodan/api/insurance/wecom/routes.py

94 lines
3.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""企微机器人路由
GET /wecom/callback 企微 URL 验证
POST /wecom/callback 企微消息接收
GET /wecom/oauth 企微 OAuth 登录入口
GET /wecom/oauth/callback 企微 OAuth 回调
"""
from flask import Blueprint, request, Response, redirect
from insurance.config import get_config as _get_wecom_config
from insurance.wecom.service import WeComService
wecom_bp = Blueprint("wecom", __name__)
wecom_service = WeComService()
@wecom_bp.route("/callback", methods=["GET"])
def verify_callback():
"""企微服务器 URL 验证GET"""
msg_signature = request.args.get("msg_signature", "")
timestamp = request.args.get("timestamp", "")
nonce = request.args.get("nonce", "")
echostr = request.args.get("echostr", "")
result = wecom_service.verify_url(msg_signature, timestamp, nonce, echostr)
return Response(result, content_type="text/plain")
@wecom_bp.route("/callback", methods=["POST"])
def receive_message():
"""企微消息接收POST
群聊:立即返回 "success",异步调 BaoDan 并主动发送到群(群聊不支持被动回复)。
私聊:同步处理,返回被动回复 XML。
"""
# 校验回调IP白名单Nginx透传 X-Forwarded-For
client_ip = request.headers.get("X-Forwarded-For", request.remote_addr or "").split(",")[0].strip()
if not wecom_service.is_callback_ip(client_ip):
print(f"[WECOM ERROR] 非法回调IP: {client_ip}", flush=True)
return Response("", status=200)
msg_signature = request.args.get("msg_signature", "")
timestamp = request.args.get("timestamp", "")
nonce = request.args.get("nonce", "")
encrypted_data = request.data
# 先判断是否群聊(群聊必须立即返回 "success"5秒内不回复会被企微重试
if wecom_service.handle_message_for_group(msg_signature, timestamp, nonce, encrypted_data):
return Response("success", status=200)
# 私聊:同步处理,返回被动回复 XML
reply_xml = wecom_service.handle_message(msg_signature, timestamp, nonce, encrypted_data)
if reply_xml:
return Response(reply_xml, content_type="application/xml", status=200)
return Response("", status=200)
@wecom_bp.route("/oauth", methods=["GET"])
def oauth_login():
"""重定向到企微授权页面。"""
corp_id = _get_wecom_config("WECOM_CORP_ID")
redirect_uri = f"{request.host_url}insurance/wecom/oauth/callback"
auth_url = (
f"https://open.weixin.qq.com/connect/oauth2/authorize"
f"?appid={corp_id}"
f"&redirect_uri={redirect_uri}"
f"&response_type=code"
f"&scope=snsapi_userinfo"
f"&state=state"
f"#wechat_redirect"
)
return redirect(auth_url)
@wecom_bp.route("/oauth/callback", methods=["GET"])
def oauth_callback():
"""企微 OAuth 回调code 换用户信息 -> 生成 JWT -> 重定向到前端。"""
code = request.args.get("code", "")
if not code:
return redirect("/login?error=auth_failed")
from insurance.auth.service import AuthService
auth_service = AuthService()
result = auth_service.wework_login(code, "")
if result.get("code") == 0:
token = result["data"]["token"]
user = result["data"].get("user", {})
import json
user_json = json.dumps(user, ensure_ascii=False)
from urllib.parse import quote
return redirect(f"/?token={token}&user={quote(user_json)}")
else:
return redirect("/login?error=auth_failed")