From a602325a3b2c9e1df99c1c5300bb043a155de7aa Mon Sep 17 00:00:00 2001 From: HuangHai <10402852@qq.com> Date: Wed, 26 Mar 2025 14:17:48 +0800 Subject: [PATCH] 'commit' --- AI/WxMini/Milvus/requirements.txt | 4 +- AI/WxMini/Start.py | 89 ++++++++++++++++++-- AI/WxMini/__pycache__/Start.cpython-310.pyc | Bin 9258 -> 9691 bytes 3 files changed, 85 insertions(+), 8 deletions(-) diff --git a/AI/WxMini/Milvus/requirements.txt b/AI/WxMini/Milvus/requirements.txt index 4948a618..a8cb3103 100644 --- a/AI/WxMini/Milvus/requirements.txt +++ b/AI/WxMini/Milvus/requirements.txt @@ -7,4 +7,6 @@ numpy==1.23.5 alibabacloud_imagerecog20190930==2.0.10 alibabacloud_tea_openapi==0.0.2 alibabacloud_sts20150401==1.1.4 -alibabacloud_credentials==2.2.1 \ No newline at end of file +alibabacloud_credentials==2.2.1 +python-jose[cryptography]==2.21 +passlib[bcrypt]== 0.6.1 diff --git a/AI/WxMini/Start.py b/AI/WxMini/Start.py index 150ef8fc..408726cb 100644 --- a/AI/WxMini/Start.py +++ b/AI/WxMini/Start.py @@ -3,22 +3,38 @@ import logging import time import uuid from contextlib import asynccontextmanager -from fastapi import Query -from fastapi import FastAPI, Form, HTTPException +from datetime import datetime, timedelta +from typing import Optional + +from fastapi import Query, Depends, HTTPException, status, Form, FastAPI +from fastapi.security import OAuth2PasswordBearer +from jose import JWTError, jwt from openai import AsyncOpenAI +from passlib.context import CryptContext + from WxMini.Milvus.Config.MulvusConfig import * from WxMini.Milvus.Utils.MilvusCollectionManager import MilvusCollectionManager from WxMini.Milvus.Utils.MilvusConnectionPool import * from WxMini.Utils.EmbeddingUtil import text_to_embedding -from WxMini.Utils.MySQLUtil import init_mysql_pool, save_chat_to_mysql, get_chat_log_by_session, update_risk, \ - get_last_chat_log_id, get_user_by_login_name, get_chat_logs_by_risk_flag -from WxMini.Utils.OssUtil import upload_mp3_to_oss_from_memory,get_sts_token +from WxMini.Utils.MySQLUtil import init_mysql_pool, save_chat_to_mysql, get_chat_log_by_session, get_user_by_login_name, \ + get_chat_logs_by_risk_flag +from WxMini.Utils.MySQLUtil import update_risk, get_last_chat_log_id +from WxMini.Utils.OssUtil import upload_mp3_to_oss_from_memory, get_sts_token from WxMini.Utils.TtsUtil import TTS # 配置日志 logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") logger = logging.getLogger(__name__) +# 配置 JWT +SECRET_KEY = "DsideaL4r5t6y7u" # 替换为你的密钥 +ALGORITHM = "HS256" +ACCESS_TOKEN_EXPIRE_MINUTES = 30 +# 密码加密上下文 +pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") +# OAuth2 密码模式 +oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") + # 初始化 Milvus 连接池 milvus_pool = MilvusConnectionPool(host=MS_HOST, port=MS_PORT, max_connections=MS_MAX_CONNECTIONS) @@ -104,6 +120,42 @@ client = AsyncOpenAI( ) +# 验证密码 +def verify_password(plain_password, hashed_password): + return pwd_context.verify(plain_password, hashed_password) + + +# 创建 JWT +def create_access_token(data: dict, expires_delta: Optional[timedelta] = None): + to_encode = data.copy() + if expires_delta: + expire = datetime.utcnow() + expires_delta + else: + expire = datetime.utcnow() + timedelta(minutes=15) + to_encode.update({"exp": expire}) + encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) + return encoded_jwt + + +# 获取当前用户 +async def get_current_user(token: str = Depends(oauth2_scheme)): + credentials_exception = HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="无法验证凭证", + headers={"WWW-Authenticate": "Bearer"}, + ) + try: + payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) + login_name: str = payload.get("sub") + if login_name is None: + raise credentials_exception + except JWTError: + raise credentials_exception + user = await get_user_by_login_name(app.state.mysql_pool, login_name) + if user is None: + raise credentials_exception + return user + # 登录接口 @app.post("/aichat/login") @@ -135,6 +187,12 @@ async def login( "success": False } + # 生成 JWT + access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) + access_token = create_access_token( + data={"sub": user["login_name"]}, expires_delta=access_token_expires + ) + # 返回带字段名称的数据 return { "code": 200, @@ -150,11 +208,12 @@ async def login( "area_name": user["area_name"], "school_name": user["school_name"], "grade_name": user["grade_name"], - "class_name": user["class_name"] + "class_name": user["class_name"], + "access_token": access_token, + "token_type": "bearer" } } - # 与用户交流聊天 @app.post("/aichat/reply") async def reply(person_id: str = Form(...), prompt: str = Form(...)): @@ -359,6 +418,22 @@ async def get_oss_upload_token(): } } +# 受保护的接口示例 +@app.get("/aichat/protected-route") +async def protected_route(current_user: dict = Depends(get_current_user)): + """ + 受保护的接口,需要 JWT 验证 + :param current_user: 当前用户(通过 JWT 验证) + :return: 用户信息 + """ + return { + "code": 200, + "message": "访问成功", + "data": { + "login_name": current_user["login_name"], + "person_name": current_user["person_name"] + } + } # 运行 FastAPI 应用 if __name__ == "__main__": diff --git a/AI/WxMini/__pycache__/Start.cpython-310.pyc b/AI/WxMini/__pycache__/Start.cpython-310.pyc index 3868f57d761f0b71e5c7168bb999e1da3d8e2cb9..b123c031b1c6249b4ab7c0e3128be98bc7f8c797 100644 GIT binary patch delta 2430 zcmZWpYiu0V6`ngYJ09=L??=|J^*YXG6F*2Ch#lJ@PO>G&_O25<4NN1AwtKIgwP$wR zJF^5wtrip`D%34RSD~szo21YOt|*bL(n@V5RDPgJ{nLLi{m~yK5dI+X6SZ-B&)w84 zbVv7_bIv{I?3wf0KKJ*zs1u0-XVd6%#8=bmwcp{4=EMe8sY~9f9dZXSB z8bKioSRp%Xgaxfxk!8@Uv!Zr`(eO~#C}g_TWH%elLRN3x`1QWB9W!Er4O(4xx6y6) z7(IdyS-p0j(T600*5ds1<1mg?WZ-Wn$iN+B>?ecd07;UAI9gGR6ggxZCJp59bz}^Y z0B#`qii{g^)0WC5!?+o@Y)Qrl(aA7wtsrBRgvleg+=kmLvT=lr-ad*u?jTZ+JMlgo ztH^@t0*broCS$mVjIF4+7x!%ixWi+@B3`w)F6^!&uG!Bu6GC$U?-!bna?Qu^AlIzJ z2l$i32P+DvQ=C3j#)t7xMSW;EOpfCba(qR@qxcbFJT8on2;)wCR0LLaGgj*c9}`{_ z{3!SErI*L>ap7e`cp1Ng@B}`wCGqf2kO4foF29mQw3pWkS(C;jnOvK~Q+OJm1HgFk*3mOOLXSad{G{ovd z!=We$dH{OaOlUtc*h(nbV>IN7Icw7`xF#iT$@1tRs0cW~wnJ+u$=bpfHOpBo6i0Sm z?|c@a4C{_12B*26U+0$cdE&aIFy}t`@gMH}>E_4Zf92jwx9Dkbv%t(4E>}t5F90k7 zECXBw_$I(5fTsYS=8#h9BGB*`^gIV&#W^p>#f>1T`998a=>kYILT|;&t*|0XN0Y9;GHT*X93UPymq_9+U*s?8$%OM9Ots`Lc=tbG9G zS#!rMI>#<|oQ=Dn`yGJ2gg(rtNZW1pZpZuGKjHV+TK|_%=vYXs$umw5vbVY}ADib2 zpTeipH4Y_c(~sYN`O`bUz5koL&@(sh@-qGu?r(AMWsA`Ho#}3hE=552e-#(O{tT{O z2Y40WYw?9^!x%)8jmLY}_FVcZ58i!KscA&$ ziBy0#f%aDe5*0{k^yhH(r3=kjS#gO+e+lAW0MvxY-i>#larQwxS-#d?n>knj4_AU1 z`8+q=`|;0^bbj9B$Av;ak38wR^gX^`u>4&KEBhpls=&ZL$wQuuwbuf;?lomeO6eJz z;Bu%S0~pG&4`hnBb&3>Z`fm&NS+eUkMMVi z7QD@6*hi^=AIS-IbDeCO1?)G~ux`~P%HP7Iy2Jd?w@dkT-Xp~v%nKrU zS(cF|Ye+*ff7E|z59m95&UfRRe(BkTLa{J%(JNT)$in8*`FS8|2t0`46J0Gf zve?*Stu-+-5z}B;X$!lSi1F#YnHWMn?9Yi)!t+L71ojPpZ2+DYo{7>k zg}g(HzCz2TVokb58;hl?PuUJGS>z-%rVEaBNk{O6`P0e|P;mC6MmdZc)gX#0s-h!V zZA5xw@TjanEwo)-56VHL?sD!wvK-#kk0g*()&pTBiqr=qRk6G)E8z!vbCA0N@mHjY NAPP3=s9jbc{1-(oZF2ws delta 2025 zcmZXUNo*Tc7{~p_HYc&OI<}M4S(~Ow>NG{^l9o`~lq6MQq++>wFR9a+O!USs zNiS~INK_!xq_3qEP!~#BiUg4?IIu`?;sOV5XgH#_^n^GdfvN=FH%^-rZ26~e{@?Px z@0%I_a`5i6KHcke+4yJI!mrc2`ulThJr9!JzDzz%5N((3fEvN*om?E`Wt5Iq! z+ojfObxIww5j0azvS_9OyRj!HfN(QJ8gC&bOd=#onn*MD=Ilxf*`maVkHpR+rIk3a zk2t3UT#QQ=MXt2rQe3uZQ`(7>wBhm`QaXs6bYefQ$O%dp>A1NSSKdNI##QIn$+H8b z8wW}El$gcUxMtD83vJ`G)~b@$qxA4rAg!*DhU;-dPJjY91Qt(kkVixe9Nyjw_Vu zd8*8ItBf7@@)8?m`f$J1!Vc1icbpQI5H07UAT_SUNqlAi$MFE($=evriTnnjaqAb` z^$;G0!|b#WU{{4lA!OEN=2Sh26WUx)BCRKM!$?d~T}x<0)9FI~JNp+1x!Am8Ko0QC zk8L!O|UK}~G0=ct#GId!3v4uNxj{*&ULM9CC!GM!}S{C81HzP+Lc zNn60%#z^HZ)Skax$#v6dWF{wxVVL#|RZX`+l63N9BAwERDdP-Hrc?SXJ;3Gy!|p4ftD%xM>z08c!TPGB&zr*c2g)K4YnTGwG9*Bry%LM}hcYFQoMW`T;utaSqcn z!ISh%dYDq3QU~Y*fSrI=z#y9o9ztIb|DHlxF==gZz$k_1ykr$~OA~x^yuV8~T z1mb>HR~279-WS3kp8#xHA-^;o*78*Ld-eCVZ*U=oOveiuLKn_>yOOEN zlgV_Ks!yk8^VdD|2wh@TzHp<}Uy=uBJRA?MeRc1fEB7xf-Fxju;T|lrmwh-p#C>!b za0T!t;40uPz%{_zfOi1za>PV>8SE$J=~zK626fY*1=T8jiQA?)r6#9o8$@kP=ZS*L zVKx6JJ6ycC@j4gI_#aO-P0|S%FTo>dGk0b7u?zKK_IFM1_9cG#5dI3O0uDI;{%02- z-unEvPgh{pD=WO$8{ogmVG1gtOZgME6di+w{J+&9P;Ud?2fPZ{=+tV|v$>xZWV0C( zj}p!Xd?KQE@@@5N2sN|TP=|CJvKc!bs?R{E_u5E%{ zKmwB1WGRenS&u^&U4jdVYh3+D5Ik#gx5w^7;%ebqSQG4?Rk_r~YptuLJggwQ!ZNB9 H#MOTRpM3j2