添加身份验证后的接口能够防止非法用户写入内容,能够节省一定的磁盘空间:
main文件内容:
from fastapi import FastAPI,Request,Depends, HTTPException, status,Form
import os,pymysql
from fastapi.encoders import jsonable_encoder ##将别的类型的数据装换成json类型的数据
from typing import Optional
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm ##用于身份验证
from jose import JWTError, jwt ##添加jwt令牌
from passlib.context import CryptContext ##添加加密算法
from model.mysql import createtable,querydb,insertdb,query ##导入数据库模块
from datetime import datetime, timedelta
from pydantic import BaseModel
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}
###定义加密信息
SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
class Token(BaseModel):
access_token: str
token_type: str
class TokenData(BaseModel):
username: Optional[str] = None
##定义用户模型
class User(BaseModel):
id: Optional[int] = None
username: Optional[str]=None
userpwd: Optional[str]=None
hashed_password: Optional[str]=None
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
app = FastAPI()
db = pymysql.connect("localhost", "root", "123456", "user")
##验证用户输入密码是否和数据库中的密码一致
def verify_password(plain_password, hashed_password):
return pwd_context.verify(plain_password, hashed_password)
##对用户密码进行加密
def get_password_hash(password):
return pwd_context.hash(password)
##查询数据库中是否有该用户名的信息
def get_user(db, username: str):
result=querydb(db,username)
if result:
return result
##判断该用户的密码是否正确
def authenticate_user(db, username: str, password: str):
user= querydb(db, username)
if not user:
return False
if not verify_password(password, user[3]):
return False
return user
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="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
token_data = TokenData(username=username)
except JWTError:
raise credentials_exception
user = get_user(db, username=token_data.username)
if user is ():
raise credentials_exception
return user
@app.post("/token", response_model=Token)
async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()):
user = authenticate_user(db, form_data.username, form_data.password)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Bearer"},
)
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token(
data={"sub": user[1]}, expires_delta=access_token_expires
)
return {"access_token": access_token, "token_type": "bearer"}
###实现保存用户传入内容并落盘的api
@app.post("/content")
async def get_content(current_user: User = Depends(get_current_user),request:Request=None):
data = await request.body() #获得用户的body信息,将传入的内容赋值给data
data = jsonable_encoder(data) #将data装换为json格式
dir=r'C:/Users/huangxinyi/Desktop/apicontenttest/' ##定义保存用户传入内容的目录
if not os.path.exists(dir):
os.makedirs(dir) ###建立文件目录
filename = dir+current_user[1] ###定义保存用户传入内容的文件名称,以用户的内容作为文件名
with open(filename,'a') as f:
f.write(data+'\n')
# return data
###注册功能
@app.post("/register")
async def register(username: str = Form(...), password: str = Form(...)):
user1=User()
user1.username=username
user1.userpwd=password
user1.hashed_password=get_password_hash(password)
db = pymysql.connect("localhost", "root", "123456", "user")
try : ##判断数据库中是否存在该user表
query(db)
except:
createtable(db)
try:
results=insertdb(db, user1)
print(results)
if results=="用户名不能重复":
raise HTTPException(status_code=400, detail="用户名不能重复")
if results=='插入数据失败!':
raise HTTPException(status_code=400, detail="注册用户失败")
finally:
db.close()
数据库的文件内容如下:
def createtable(db):
# 使用cursor()方法获取操作游标
cursor = db.cursor()
cursor.execute("DROP TABLE IF EXISTS user")
sql = """CREATE TABLE user (
ID int PRIMARY KEY auto_increment,
username VARCHAR(20) UNIQUE,
userpwd VARCHAR(50),
hashed_password VARCHAR(200))"""
# 创建Sutdent表
cursor.execute(sql)
##向数据库中插入数据
def insertdb(db,user):
# 使用cursor()方法获取操作游标
cursor = db.cursor()
if querydb(db,user.username):
return "用户名不能重复"
# # SQL 插入语句
sql = "INSERT INTO user(username, userpwd, hashed_password) \
VALUES ('%s', '%s', '%s')" % \
(user.username,user.userpwd,user.hashed_password)
print(sql)
try:
# 执行sql语句
cursor.execute(sql)
# 提交到数据库执行
db.commit()
except:
db.rollback()
return '插入数据失败!'
##根据指定用户名去查询用户信息
def querydb(db,username):
# 使用cursor()方法获取操作游标
cursor = db.cursor()
sql = "SELECT * FROM user WHERE username = '" +username + "'"
print(sql)
try:
# 执行SQL语句
cursor.execute(sql)
# 获取所有记录列表
results = cursor.fetchall()[0]
return list(results)
except:
return False
##判断数据库是否为空
def query(db):
cursor = db.cursor()
sql = "SELECT * FROM user "
cursor.execute(sql)
results = cursor.fetchall()
if results:
return True
else:
return False
def closedb(db):
db.close()
可以通过交互式文档获得相应的语句,并且去执行post操作,实现保存用户传入内容落盘。
可以看到该api后面有一个锁的标志,即说明该api进行了身份验证的安全性操作,点击锁的标志,进行身份验证(在身份验证之前需要先创建一个合法的用户,点击register的api创建合法用户):
创建合法用户之后就可以登录,才能验证成功:
至此,用户已经成功登录,然后点击try it out获得其认证信息:
然后在cmd命令行中输入红色部分的内容,-d选项即为用户要传入的内容
可以看到在指定的文件目录下,已经存在了以该用户名为名字的文件: