如何在FastAPI中实现请求的身份验证和授权

1. FastAPI简介

FastAPI是一个基于Python的现代Web框架,由于其快速、易用和自动文档化等优点,在Python社区内备受关注,并且正在成为web开发的热门选择。FastAPI提供了很多功能来简化Web API的开发,其中包括强类型注释、高性能、自动文档化、请求数据验证、异步支持等,这些特性都将在本文中得到应用与实践。

2. 认证和授权的定义和概念

在讨论FastAPI如何进行身份验证和授权之前,先确定一下认证和授权的定义和概念。

2.1 认证

认证(Authentication)是指验证用户身份的过程。一般情况下,在Web应用程序中,认证有用户名和密码等凭证类型,通常被称为“用户凭证”。

2.2 授权

授权(Authorization)是指确定一个用户是否具有访问某个资源或执行某个操作的权限的过程。在Web应用程序中,授权通常是使用访问令牌(Access Tokens)和角色(Role)来管理用户的访问权限的机制。

3. FastAPI如何实现身份验证(Authentication)

在FastAPI中实现身份验证,可以利用FastAPI提供的依赖注入机制(Dependency Injection)和Pydantic库的模型定义特性,来创建一个认证模型,然后在路由中使用该模型进行身份验证。

3.1 创建认证模型(Authentication Model)

在FastAPI中,创建身份验证的第一步是定义一个认证模型,该模型负责接收请求中发送的所有认证信息,并对其进行验证。在本文中,我们将使用HTTP Basic认证,其中客户端提供的用户名和密码以Base 64编码方式存储在Authorization请求头内。

首先,我们需要设置一个常量,含有Base64编码的用户名和密码后的字符串,用于与Request Headers中的Authorization请求头部的base64编码值进行比较,来检查用户名和密码是否正确。

import base64

API_KEY = 'mysecretkey'

encoded_key = base64.b64encode(bytes(f"apikey:{API_KEY}", 'utf-8'))

在定义了常量后,我们可以定义一个认证模型。在本文中,我们将认证信息存储在UsernamePassword模型中,并使用@fastapi.depends装饰器将该模型注入路由中。

from fastapi import Depends, FastAPI, HTTPException

from fastapi.security import HTTPBasic, HTTPBasicCredentials

from pydantic import BaseModel

app = FastAPI()

security = HTTPBasic()

class UsernamePassword(BaseModel):

username: str

password: str

# 通过API KEY进行验证

def verify_key(api_key: str = Depends(HTTPBasicCredentials())):

decoded_key = base64.b64decode(api_key.credentials).decode('utf-8')

if decoded_key != f"apikey:{API_KEY}":

raise HTTPException(status_code=401, detail="Incorrect API Key")

# 用户名密码进行验证

def verify_password(user_pass: UsernamePassword):

correct_username = "user"

correct_password = "password"

if user_pass.username != correct_username or user_pass.password != correct_password:

raise HTTPException(status_code=401, detail="Incorrect email or password")

@app.get("/")

async def root(username_password: UsernamePassword, api_key: HTTPBasicCredentials = Depends(security)):

verify_password(username_password)

verify_key(api_key)

return {"message": "Successful authentication"}

在上述代码中,我们使用了fastapi.security常见的HTTPBasic类,来实现HTTP Basic认证方式。HTTPBasic.security()提供了如下方法来验证认证信息:

def __call__(self, request: Request) -> Tuple[str, Optional[str]] - 获取并验证UserCredentials

async def get_login_from_credentials(self, credentials: HTTPBasicCredentials) -> str: - 从HTTPBasicCredentials中获取用户名

async def verify_password(self, plain_password: str, hashed_password: str) -> bool: - 验证密码是否与哈希密码匹配

async def authenticate(self, request: Request) -> Union[Tuple[Any, Any], None]: - 在身份验证上执行任何其他步骤,如:LDAP,OAuth等。

4. FastAPI如何实现授权(Authorization)

在FastAPI中实现授权,可以使用OAuth2规范的认证授权机制来管理访问令牌和角色。OAuth2认证授权协议指定了四种角色——资源所有者(Resource Owner),客户端(Client),授权服务器(Authorization Server)和资源服务器(Resource Server),本文将聚焦于如何使用OAuth2规范的认证授权机制在FastAPI应用中实现授权。

4.1 多种OAuth2认证方案的实现

在FastAPI中使用OAuth2作为认证授权机制的方式,共享与其他框架的通用性。FastAPI支持OAuth2的多种认证授权机制,包括:

Authorization code:采用最高安全性的认证授权机制,控制了访问令牌的分发。详见RFC 6749 Section 4.1

Implicit:在客户端流程中跳过授权服务器中的授权码流程。详见RFC 6749 Section 4.2

Resource Owner Password Credentials:应用程序直接从资源所有者获取凭证,使用用户名和密码进行身份验证。详见RFC 6749 Section 4.3

Client Credentials:应用程序使用其自身的凭证(而不是用户),使用客户端身份验证来直接与资源服务器进行通信。详见RFC 6749 Section 4.4

Device Flow:允许在资源拥有者的设备上进行身份验证,但不需要在其中打开Web浏览器。详见RFC 8628

下面将以Resource Owner Password Credentials方案为例,详细说明如何在FastAPI中使用OAuth2机制实现授权。

4.2 创建授权模型(Authorization Model)

在实现授权的过程中,我们需要定义一个授权模型,用于存储授权访问令牌(Token)。在FastAPI中,一个Pydantic模型可以实现这一目的。

from pydantic import BaseModel

class AccessToken(BaseModel):

access_token: str

token_type: str

在创建了授权模型后,我们需要创建一个返回授权访问令牌的对象。在本文中,我们将使用用户名和密码来获取相应的Access Token。

ACCESS_TOKEN_EXPIRE_MINUTES = 30

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

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 authenticate_user(username: str, password: str):

user = get_user(username)

if not user:

return False

if not verify_password(password, user.hashed_password):

return False

return user

@app.post("/token", response_model=AccessToken)

async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()):

user = await authenticate_user(form_data.username, form_data.password)

if not user:

raise HTTPException(status_code=400, detail="Incorrect username or password")

access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)

access_token = create_access_token(

data={"sub": user.username}, expires_delta=access_token_expires

)

return {"access_token": access_token, "token_type": "bearer"}

在以上代码中,我们使用HTTPException来处理错误情况,同时使用get_user()函数和verify_password()函数来验证用户名和密码是否正确。get_user()函数负责从数据库中获取用户信息,而verify_password()函数负责验证传递的密码与哈希密码是否匹配。

总结

本文主要讲解了如何在FastAPI中实现身份验证和授权。使用FastAPI是快速、可扩展、易用的,它为Web API开发提供了很多特性。在本文中,我们通过使用Depends注入机制和Pydantic模型来实现身份验证,使用OAuth2规范的认证授权机制来管理访问令牌和角色。这样可以加强Web应用程序的安全性,并更好的控制和管理访问。

后端开发标签