区分环境
This commit is contained in:
parent
78e744143f
commit
381a95654a
1
.gitignore
vendored
1
.gitignore
vendored
@ -38,6 +38,5 @@ ENV/
|
||||
*.log
|
||||
|
||||
# Local development
|
||||
.env
|
||||
.env.local
|
||||
*.db
|
||||
@ -44,7 +44,7 @@ async def wechat_phone_login(
|
||||
):
|
||||
"""通过微信手机号登录/注册"""
|
||||
try:
|
||||
# 初始化微信客户端
|
||||
# 初始化微信客户端
|
||||
wechat = WeChatClient()
|
||||
|
||||
# 获取用户 openid
|
||||
@ -66,17 +66,17 @@ async def wechat_phone_login(
|
||||
if not phone:
|
||||
return error_response(code=400, message="手机号为空")
|
||||
|
||||
# # 获取企业微信的 userid
|
||||
wecom_client = WecomClient()
|
||||
wecom_info = await wecom_client.miniprogram_to_userid(openid=openid)
|
||||
print(f"获取到的企业微信用户信息: {wecom_info}")
|
||||
# # # 获取企业微信的 userid
|
||||
# wecom_client = WecomClient()
|
||||
# wecom_info = await wecom_client.miniprogram_to_userid(openid=openid)
|
||||
# print(f"获取到的企业微信用户信息: {wecom_info}")
|
||||
|
||||
wecom_userid = None
|
||||
wecom_pending_id = None
|
||||
# wecom_userid = None
|
||||
# wecom_pending_id = None
|
||||
|
||||
if wecom_info:
|
||||
wecom_userid = wecom_info.get("userid")
|
||||
wecom_pending_id = wecom_info.get("pending_id")
|
||||
# if wecom_info:
|
||||
# wecom_userid = wecom_info.get("userid")
|
||||
# wecom_pending_id = wecom_info.get("pending_id")
|
||||
|
||||
|
||||
# 查找或创建用户
|
||||
@ -93,8 +93,8 @@ async def wechat_phone_login(
|
||||
password=get_password_hash("123456"),
|
||||
openid=openid, # 保存 openid
|
||||
unionid=unionid, # 保存 unionid
|
||||
wecom_userid=wecom_userid,
|
||||
wecom_pending_id=wecom_pending_id
|
||||
# wecom_userid=wecom_userid,
|
||||
# wecom_pending_id=wecom_pending_id
|
||||
)
|
||||
db.add(user)
|
||||
db.flush()
|
||||
@ -106,8 +106,8 @@ async def wechat_phone_login(
|
||||
# 更新现有用户的 openid 和 unionid
|
||||
user.openid = openid
|
||||
user.unionid = unionid
|
||||
user.wecom_userid = wecom_userid
|
||||
user.wecom_pending_id = wecom_pending_id
|
||||
# user.wecom_userid = wecom_userid
|
||||
# user.wecom_pending_id = wecom_pending_id
|
||||
db.commit()
|
||||
|
||||
# 创建访问令牌
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
from typing import Optional
|
||||
from pydantic_settings import BaseSettings
|
||||
import os
|
||||
from functools import lru_cache
|
||||
|
||||
class Settings(BaseSettings):
|
||||
DEBUG: bool = True # 开发模式标志
|
||||
@ -108,4 +110,49 @@ class Settings(BaseSettings):
|
||||
env_file = ".env"
|
||||
extra = "allow" # 允许额外的环境变量
|
||||
|
||||
settings = Settings()
|
||||
class DevSettings(Settings):
|
||||
DEBUG: bool = True # 开发模式标志
|
||||
API_V1_STR: str = "/api/v1"
|
||||
PROJECT_NAME: str = "FastAPI 项目 (开发环境)"
|
||||
|
||||
MYSQL_HOST: str = "gz-cynosdbmysql-grp-2j1cnopr.sql.tencentcdb.com"
|
||||
MYSQL_PORT: int = 27469
|
||||
MYSQL_USER: str = "root"
|
||||
MYSQL_PASSWORD: str = "Aa#223388"
|
||||
MYSQL_DB: str = "beefast"
|
||||
|
||||
class Config:
|
||||
env_file = ".env.dev"
|
||||
|
||||
class ProdSettings(Settings):
|
||||
DEBUG: bool = False # 生产模式标志
|
||||
API_V1_STR: str = "/api/v1"
|
||||
PROJECT_NAME: str = "FastAPI 项目 (生产环境)"
|
||||
|
||||
MYSQL_HOST: str = "cd-cynosdbmysql-grp-7kdd8qe4.sql.tencentcdb.com"
|
||||
MYSQL_PORT: int = 26558
|
||||
MYSQL_USER: str = "root"
|
||||
MYSQL_PASSWORD: str = "Ss@123!@#"
|
||||
MYSQL_DB: str = "beefast"
|
||||
|
||||
class Config:
|
||||
env_file = ".env.prod"
|
||||
|
||||
|
||||
@lru_cache()
|
||||
def get_settings() -> BaseSettings:
|
||||
"""
|
||||
获取配置实例
|
||||
使用环境变量 APP_ENV 来决定使用哪个配置
|
||||
"""
|
||||
env = os.getenv("APP_ENV", "dev").lower()
|
||||
config_map = {
|
||||
"dev": DevSettings,
|
||||
"prod": ProdSettings
|
||||
}
|
||||
|
||||
config_class = config_map.get(env, DevSettings)
|
||||
return config_class()
|
||||
|
||||
# 导出配置实例
|
||||
settings = get_settings()
|
||||
@ -1,93 +1,130 @@
|
||||
import aiohttp
|
||||
from app.core.config import settings
|
||||
import requests
|
||||
import json
|
||||
import time
|
||||
import logging
|
||||
from typing import Optional, Dict
|
||||
from app.core.config import settings
|
||||
from typing import Dict, Any, Optional, List
|
||||
|
||||
class WecomClient:
|
||||
"""企业微信客户端"""
|
||||
|
||||
def __init__(self):
|
||||
self.corpid = settings.WECHAT_CORP_ID
|
||||
self.secret = settings.WECHAT_CORP_SECRET # 注意:这里使用普通的 secret,不是 provider_secret
|
||||
self.corp_id = settings.WECHAT_CORP_ID
|
||||
self.corp_secret = settings.WECHAT_CORP_SECRET
|
||||
self.access_token = None
|
||||
|
||||
self.token_expires_at = 0
|
||||
|
||||
async def get_access_token(self) -> str:
|
||||
"""获取企业微信普通access_token"""
|
||||
"""获取访问令牌"""
|
||||
# 检查令牌是否过期
|
||||
if self.access_token and time.time() < self.token_expires_at:
|
||||
return self.access_token
|
||||
|
||||
# 获取新令牌
|
||||
url = f"https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={self.corp_id}&corpsecret={self.corp_secret}"
|
||||
|
||||
try:
|
||||
url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken"
|
||||
params = {
|
||||
"corpid": self.corpid,
|
||||
"corpsecret": self.secret
|
||||
}
|
||||
response = requests.get(url)
|
||||
result = response.json()
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(url, params=params) as response:
|
||||
result = await response.json()
|
||||
|
||||
if result.get("errcode") == 0:
|
||||
self.access_token = result["access_token"]
|
||||
print(f"企业微信access_token: {self.access_token}")
|
||||
return self.access_token
|
||||
else:
|
||||
logging.error(f"获取access_token返回: {result}")
|
||||
raise Exception(f"获取access_token失败: {result}")
|
||||
|
||||
if result.get("errcode") == 0:
|
||||
self.access_token = result.get("access_token")
|
||||
self.token_expires_at = time.time() + result.get("expires_in") - 200 # 提前200秒过期
|
||||
return self.access_token
|
||||
else:
|
||||
logging.error(f"获取企业微信访问令牌失败: {result}")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"获取access_token失败: {str(e)}")
|
||||
raise
|
||||
|
||||
async def miniprogram_to_userid(self, openid: str) -> Optional[Dict]:
|
||||
"""
|
||||
转换小程序身份到企业微信
|
||||
可以使用code或openid
|
||||
"""
|
||||
try:
|
||||
# 构建请求参数
|
||||
url = "https://qyapi.weixin.qq.com/cgi-bin/miniprogram/jscode2session"
|
||||
params = {
|
||||
"access_token": await self.get_access_token(),
|
||||
"appid": settings.WECHAT_APPID,
|
||||
}
|
||||
|
||||
# 根据传入参数类型选择
|
||||
params["openid"] = openid
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(url, params=params) as response:
|
||||
result = await response.json()
|
||||
logging.info(f"转换结果: {result}")
|
||||
|
||||
if result.get("errcode") == 0:
|
||||
return {
|
||||
"userid": result.get("userid"), # 如果是企业成员,返回userid
|
||||
"pending_id": result.get("pending_id"), # 如果是外部联系人,返回pending_id
|
||||
"openid": result.get("openid"),
|
||||
"session_key": result.get("session_key")
|
||||
}
|
||||
else:
|
||||
logging.error(f"身份转换失败: {result}")
|
||||
return None
|
||||
except Exception as e:
|
||||
logging.error(f"身份转换失败: {str(e)}")
|
||||
logging.exception(f"获取企业微信访问令牌异常: {str(e)}")
|
||||
return None
|
||||
|
||||
async def get_user_info(self, userid: str) -> Optional[Dict]:
|
||||
"""获取企业成员信息"""
|
||||
try:
|
||||
url = "https://qyapi.weixin.qq.com/cgi-bin/user/get"
|
||||
params = {
|
||||
"access_token": await self.get_access_token(),
|
||||
"userid": userid
|
||||
}
|
||||
|
||||
async def miniprogram_to_userid(self, openid: str) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
小程序openid转换为企业微信userid
|
||||
|
||||
Args:
|
||||
openid: 小程序用户的openid
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(url, params=params) as response:
|
||||
result = await response.json()
|
||||
|
||||
if result.get("errcode") == 0:
|
||||
return result
|
||||
else:
|
||||
logging.error(f"获取用户信息失败: {result}")
|
||||
return None
|
||||
|
||||
Returns:
|
||||
Dict: 包含userid或pending_id的字典
|
||||
"""
|
||||
token = await self.get_access_token()
|
||||
if not token:
|
||||
return None
|
||||
|
||||
url = f"https://qyapi.weixin.qq.com/cgi-bin/miniprogram/jscode2session?access_token={token}"
|
||||
|
||||
data = {
|
||||
"code": openid,
|
||||
"grant_type": "authorization_code"
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(url, json=data)
|
||||
result = response.json()
|
||||
|
||||
if result.get("errcode") == 0:
|
||||
return {
|
||||
"userid": result.get("userid"),
|
||||
"pending_id": result.get("pending_id")
|
||||
}
|
||||
else:
|
||||
logging.error(f"小程序openid转换失败: {result}")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"获取用户信息失败: {str(e)}")
|
||||
return None
|
||||
logging.exception(f"小程序openid转换异常: {str(e)}")
|
||||
return None
|
||||
|
||||
async def get_user_in_group_chat(self, userid: str) -> List[str]:
|
||||
"""
|
||||
获取用户所在的群聊列表
|
||||
|
||||
Args:
|
||||
userid: 企业微信用户ID
|
||||
|
||||
Returns:
|
||||
List[str]: 群聊ID列表
|
||||
"""
|
||||
token = await self.get_access_token()
|
||||
if not token:
|
||||
return []
|
||||
|
||||
url = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/list_group_chat?access_token={token}"
|
||||
|
||||
# 先获取所有群聊
|
||||
try:
|
||||
response = requests.post(url, json={})
|
||||
result = response.json()
|
||||
|
||||
if result.get("errcode") != 0:
|
||||
logging.error(f"获取群聊列表失败: {result}")
|
||||
return []
|
||||
|
||||
chat_ids = []
|
||||
for chat in result.get("group_chat_list", []):
|
||||
chat_id = chat.get("chat_id")
|
||||
|
||||
# 获取群聊详情
|
||||
detail_url = f"https://qyapi.weixin.qq.com/cgi-bin/externalcontact/groupchat/get?access_token={token}"
|
||||
detail_response = requests.post(detail_url, json={"chat_id": chat_id})
|
||||
detail_result = detail_response.json()
|
||||
|
||||
if detail_result.get("errcode") == 0:
|
||||
group_chat = detail_result.get("group_chat", {})
|
||||
members = group_chat.get("member_list", [])
|
||||
|
||||
# 检查用户是否在群内
|
||||
for member in members:
|
||||
if member.get("userid") == userid:
|
||||
chat_ids.append(chat_id)
|
||||
break
|
||||
|
||||
return chat_ids
|
||||
|
||||
except Exception as e:
|
||||
logging.exception(f"获取用户群聊异常: {str(e)}")
|
||||
return []
|
||||
|
||||
wecom_client = WecomClient()
|
||||
@ -35,6 +35,14 @@ app.add_middleware(
|
||||
# 添加请求日志中间件
|
||||
app.add_middleware(RequestLoggerMiddleware)
|
||||
|
||||
@app.get("/api/info")
|
||||
async def get_info():
|
||||
"""获取当前环境信息"""
|
||||
return {
|
||||
"project": settings.PROJECT_NAME,
|
||||
"debug": settings.DEBUG
|
||||
}
|
||||
|
||||
# 添加用户路由
|
||||
app.include_router(dashboard.router, prefix="/api/dashboard", tags=["仪表盘"])
|
||||
app.include_router(wechat.router,prefix="/api/wechat",tags=["微信"])
|
||||
|
||||
Loading…
Reference in New Issue
Block a user