PdServer(pythonAPI服务框架):快速开始
PdServer是一个pythonAPI服务器,我相信当你在看到这篇内容时,你是真的需要一个可以实现各项功能的python API服务器,以实现为你的其它业务提供能力的需求。毕竟目前python拥有足够多的开源库,例如我们的爬虫,情感分析。
项目整体代码结构,我们已经在上一篇讲解,不太清楚可以先去了解一下。
在这篇文章中,我们将以实现一个login接口来进行演示,login非常重要,因为要获取token,这需要我们在每一个业务接口中带上,实现对用户的鉴权,否则不能执行。
在这个过程中,我们需要:
-
路由中接收一个"login"请求;
-
查询数据库进行鉴权;
-
JWT生成token;
-
将userinfo与token返回;
这个过程,我们基本上跑通了流程,当然其它的一些我们会在会续的文章中分享。
-
配置端口
SERVER_PORT作为监听端口,其源于config.ini配置项,由于需要在初次运行后,才会自动生成config.ini,因此,你可以在初始化配置中修改端口,如果你已经运行过,就会自动生成这个config.ini,可以在config.ini中去修改端口。
修改初始配置如下图所示,在PdBaseKits-tools-ini中,找到initialSysConfig方法可以看到初始配置。
initialSysConfig()
#配置端口
server = {
'port' : 8062,
}
(代码中初始化配置)
如果已经有了配置文件,在界面的系统设置中可以看到文件路径:
(config.ini)
-
配置路由
为了可以接收一个请求,我们需要配置我们的路由。如果你对路由没有概念,你可以把它认为就是服务器处理请求的入口。
-
路由前缀
这不是必须的,你可以复用我们的配置,但如果你希望修改的话,你可以在server-APP下server.py完成了服务器的启动配置。路由前缀就是请求“http://localhost:8062/v1/api/trigger/login”中的“/v1/api/trigger/”部分。
其中'prefix'定义了路由的前缀,可以根据你自己的业务需求进行修改,同时可以看到,刚刚修改的port最终在这里使用。
def register_blueprints(_app):
from server.router import router
_app.include_router(router.router, prefix="/v1/api/trigger")
def run(host, port):
_app = init_app()
uvicorn.run(_app, port=port, host=host)
-
路由配置
为了让服务器可以处理我们的请求,我们需要配置我们的路由,在server-router目录下。
打开这个文件可以配置一个login请求处理,如下所示。
@router.post("/login", response_model=UserLoginResponse)
async def login(body: User):
return {"user": 'zyy', "id": "12", 'token': 'testteststesttest', 'nickname': 'dean', 'headUrl': 'i.png'}
将其设置为post请求,'/login'是路由,body是request,我们定义为User结构,response_model是响应的结构,定义为UserLoginResponse。我们将结构体的定义在schema.py中。
class User(BaseModel):
user: str
pwd: str
class UserLoginResponse(BaseModel):
user: str
id: int
token: str
nickname: str
headUrl: str
你可以根据自己的业务需求进行修改调整。
数据返回我们通过return完成,这需要保证返回JSON与response_model指定类型是一致的,否则会报错。
-
密码解密
我们配置了AES的加解密,我们默认你的登陆使用了AES进行加密,因此,我们需要先进行解密。
我习惯于将业务代码脱离router,因此,在我们的server-service下,我们可以写我们的业务代码。
在这里我新建了一个login方法,其对pwd进行解密。
class klingService:
def login(self,userId, pwd):
try:
pwdDecrypt = aesECBDecrypt(pwd)
except Exception as e:
return False
print("pwdDecrypt:"+pwdDecrypt)
#默认登陆成功
return True
现在路由中的代码也需要引用这个login方法。
midService = klingService()
logging.info("login ["+body.user+"],["+body.pwd+"]]")
if midService.login(body.user, body.pwd):
return {"user": 'zyy', "id": "12", 'token': "testtesttest", 'nickname': 'dean', 'headUrl': 'i.png'}
else:
return ""
和刚才的返回默认值相比,我们多了login的调用,但返回数据依然是模拟的。下一步我们将通过id,pwd去DB中校验,其相关的代码我们也会写到这个service中。
-
数据库访问
我们并没有像mybatis那样实现ORM,当然python也有自己的orm库,但我们并没有实现,这主要是因为我们的python应用,目前还没有需要大量的数据库访问,你可以自己去实现。相关代码在PdBaseKits-sql中。
DbBase.py实现了基础的连接和关闭,数据库的账号密码在config.ini中配置,我需要自建一个UserRegDao.py来实现用户表的读取,这个类需要继承DbBase类。在这里,我们需要自已来拼接一个SQL语句。
import logging
from typing import Union
from PdBaseKits.exceptions.exceptions import SqlConnectError
from PdBaseKits.sql.DbBase import DbBase
from entity.UserInfo import UserInfo
class UserRegDao(DbBase):
def __init__(self):
logging.info("UserRegDao")
super().__init__()
# 析构方法
def __del__(self):
super().__del__()
def chkUserInfo(self, userName:str, pwd:str)->Union[UserInfo,bool]:
sql = "select * from userinfo where username='"+userName+"' and password='"+pwd+"'"
print(sql)
data, c = self.exeStockSql(sql)
if not data:
return False
for r in data:
id=r[0]
userName = r[1]
userInfo = UserInfo(id, userName)
return userInfo
我们在这里创建了一个UserInfo类,用来承接用户信息数据:
class UserInfo():
def __init__(self,id,user):
self.id = id
self.user = user
id:int
user: str
然后,我们将这个dao层的调用写到service中,如下所示:
class klingService:
def login(self,userId, pwd):
try:
pwdDecrypt = aesECBDecrypt(pwd)
user = UserRegDao()
except Exception as e:
return False
print("pwdDecrypt:"+pwdDecrypt)
return user.chkUserInfo(userId, pwdDecrypt)
我们看到,和之前相比,多了chkUserInfo()方法的调用。这样,我们就是真实的通过数据库来判断用户是否存在。
同时,我们的router中也可以获取用户信息了,我们需要改写一下,不再使用默认数据。
@router.post("/login", response_model=UserLoginResponse)
async def login(body: User):
midService = klingService()
logging.info("login ["+body.user+"],["+body.pwd+"]]")
userInfo = midService.login(body.user, body.pwd)
if userInfo:
return {"user": userInfo.user, "id": userInfo.id, 'token': "testtest"ken, 'nickname': 'dean', 'headUrl': 'i.png'}
else:
return ""
-
JWT生成token
在前面的代码中,我们只需要在router中login方法下,增加两行生成token的方法,并用这个真实生成的token去替代之前的“testtesttest”数据。
@router.post("/login", response_model=UserLoginResponse)
async def login(body: User):
midService = klingService()
logging.info("login ["+body.user+"],["+body.pwd+"]]")
userInfo = midService.login(body.user, body.pwd)
if userInfo:
accessTokenExpires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
accessToken = create_access_token(data={"userName": body.user,'id': userInfo.id}, expires_delta=accessTokenExpires)
return {"user": userInfo.user, "id": userInfo.id, 'token': accessToken, 'nickname': 'dean', 'headUrl': 'i.png'}
else:
return ""
好了,我们的login到这里,已经从最初的返回一条默认数据,到现在完成了全部的功能。
-
运行
在完成router/service/UserRegDao后,打开serverMain.py文件,点击pyCharm右上角的运行当前文件,启动了我们的UI,然后点击“启动服务”按钮。在终端上看到如下提示说明启动成功!
我们通过apifox调试一下:
请求链接如下,这里的vi/api/trigger就是我们前文所说的前缀:
http://localhost:8062/v1/api/trigger/login
POST请求内容在body中,使用json:
然后发送请求:
完美!接口顺利运行,请求获得了响应!
-
总结
在今天的内容中,我们分享了使用PdServer实现了一个login接口。在这个过程中学习了使用数据库,解密,token生成等。整个过程十分简单,你只要按步骤一步一步来即可。如果你有任何的问题、建议,欢迎与我们联系。私信不经常看,欢迎直接加微信(cdszsz)!或关注公众号:AIGC中文站!认准咱们的头像。
原文地址:https://blog.csdn.net/zyysql/article/details/142286815
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!