fastapi是一个异步编程框架,有非常不错的性能,本文介绍如何在 fastapi中实现jwt验证功能
1. 添加依赖
pipenv install pyjwt 'passlib[bcrypt]'
2. 编写一个handle处理jwt所需功能 app/auth.py
import jwt
from fastapi import HTTPException, Security
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from passlib.context import CryptContext
from datetime import datetime, timedelta
class AuthHandler():
security = HTTPBearer()
pwd_context = CryptContext(schemes=['bcrypt'], deprecated='auto')
secret = 'SECRET'
# 密码加密
def get_password_hash(self, password):
return self.pwd_context.hash(password)
# 密码校验
def verify_password(self, plain_password, hashed_password):
return self.pwd_context.verify(plain_password, hashed_password)
# token生成
def encode_token(self, user_id):
payload = {
'exp': datetime.utcnow()+timedelta(days=0, minutes=120),
'iat': datetime.utcnow(),
'sub': user_id
}
return str(jwt.encode(payload, self.secret, algorithm='HS256'))
# token 解码
def decode_token(self, token):
try:
payload = jwt.decode(token, self.secret, algorithms=['HS256'])
return payload['sub']
except jwt.ExpiredSignatureError:
raise HTTPException(
status_code=401, detail='Signature has expired')
except jwt.InvalidTokenError as e:
raise HTTPException(status_code=401, detail='Invalid token')
def auth_wrapper(self, oauth: HTTPAuthorizationCredentials = Security(security)):
return self.decode_token(oauth.credentials)
实现一个注册方法
# 控制器方法
@router.post('/register',status_code=201)
async def register(
user:UserModel
):
user = Users(name=user.name,pwd=auth.get_password_hash(user.pwd))
# logger.info(f'user:{user.name},pwd:{user.pwd}')
await user.save()
return {'msg':user.id}
# 用户模型类
from tortoise.models import Model
from tortoise import fields
class Users(Model):
id=fields.IntField(pk=True)
name=fields.CharField(max_length=20)
pwd=fields.CharField(max_length=255)
created_at=fields.DatetimeField(auto_now_add=True)
updated_at=fields.DatetimeField(auto_Now=True)
用户登录获取Token
@router.post('/login')
async def users(user_vo:UserModel):
user_db =await Users.get(name=user1.name)
flag:bool=auth.verify_password(user_vo.pwd,user_db.pwd)
if not flag:
raise HTTPException(status_code=401,detail={
'code':1000,
'msg':'用户帐号没有授权'})
token:str=auth.encode_token(user_db.id)
return {
"id":user_db.id,
'name':user_db.name,
'token':token
}
路由保护
from fastapi import APIRouter,HTTPException,Body,Form,Depends,BackgroundTasks
from fastapi.responses import FileResponse
from pydantic import BaseModel
from .models.users import Users
from app.auth import AuthHandler
from app.logger import logger
@router.get('/test') #解码成功后返回用户id
async def test(uid=Depends(auth.auth_wrapper)):
return {'result':'ok'}