1、实现login路由白名单获取Token
2、对非白名单的路由进行鉴权
2.1 检查headers里是否包含鉴权信息
2.2 检查是否Token过期或非法Token
安装pyjwt包 pip install pyjwt 'passlib[bcrypt]'
实现JWT 生成和解码类
class AuthHandle():
security=HTTPBearer()
pwd_context=CryptContext(schemes=['bcrypt'],deprecated='auto')
secret=settings.JWT_SECRET_KEY
# 生成Token
async def encode_token(self,user_id:int)->str:
payload= {
'exp': datetime.now()+timedelta(days=0,minutes=120),
'sub': str(user_id)
}
return jwt.encode(payload,self.secret,algorithm='HS256')
# 验证Token
async def decode_token(self,token):
try:
payload=jwt.decode(token,self.secret,algorithms=['HS256'])
return payload['sub']
except jwt.ExpiredSignatureError:
raise AuthException(message='令牌已过期')
except jwt.InvalidTokenError:
raise AuthException(message='无效令牌')
# 异常类
class AuthException(Exception):
def __init__(self,message):
super().__init__(message)
中间件过滤白名单 WHITE_LIST=['/user/login']
from settings import WHITE_LIST,TOKEN_INVALID_ERROR
class TokenMiddleware(BaseHTTPMiddleware):
def __init__(self,app):
super().__init__(app)
async def dispatch(self,req:Request,call_next):
# 不在白名单内 提示未授权
if not req.url.path in WHITE_LIST:
# 需要通过JWT鉴权
if 'Authorization' not in req.headers or not req.headers['Authorization']:
return Response(content=json.dumps(TOKEN_INVALID_ERROR),status_code=status.HTTP_401_UNAUTHORIZED)
# 去掉Bearer
token=req.headers['Authorization'][7:]
auth=AuthHandle()
try:
await auth.decode_token(token)
except AuthException as e:
TOKEN_INVALID_ERROR['msg']=f'{e}'
return Response(content=json.dumps(TOKEN_INVALID_ERROR),
status_code=status.HTTP_401_UNAUTHORIZED
)
最终在app.add_middleware(TokenMiddleware)绑定实现