FastAPI学习最后一天: Cors跨域和token鉴权
在FastAPI中配置CORS时,我们可以通过CORSMiddleware
中间件来设置不同的限制。以下是几个具体的限制示例:
示例1:限制特定的源
在这个例子中,我们只允许来自http://example.com
的跨域请求。
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
origins = ["http://example.com"]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/")
async def main():
return {"message": "Hello World"}
示例2:使用正则表达式限制源
这里我们使用正则表达式来允许所有以http://example.com
开头的域名进行跨域请求。
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origin_regex=r"https?://example\.com",
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/")
async def main():
return {"message": "Hello World"}
示例3:限制特定的HTTP方法
在这个例子中,我们只允许GET
和POST
方法的跨域请求。
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
origins = ["http://example.com"]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["GET", "POST"],
allow_headers=["*"],
)
@app.get("/")
async def main():
return {"message": "Hello World"}
@app.post("/post")
async def post():
return {"message": "POST request received"}
示例4:限制特定的请求头
这里我们只允许Content-Type
和X-Custom-Header
两个请求头。
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
origins = ["http://example.com"]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["Content-Type", "X-Custom-Header"],
)
@app.get("/")
async def main():
return {"message": "Hello World"}
示例5:不允许凭据
在这个例子中,我们不允许跨域请求携带凭据(如Cookies)。
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
origins = ["http://example.com"]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=False,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/")
async def main():
return {"message": "Hello World"}
这些示例展示了如何在FastAPI中使用CORSMiddleware
来设置不同的CORS策略限制。根据你的应用需求,你可以选择适合的配置来确保应用的安全性和功能性。
在FastAPI中,你可以通过请求头中的Token来实现对所有接口的鉴权,并且可以设置某些接口不需要鉴权。以下是具体的实现方法和示例代码:
1. 使用依赖项实现Token鉴权
首先,你需要一个依赖项函数来解析和验证Token。这个函数将从请求头中获取Token,并进行验证。
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from jose import JWTError, jwt
# 配置项
SECRET_KEY = "your_secret_key"
ALGORITHM = "HS256"
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")
# 验证Token的依赖项函数
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
except JWTError:
raise credentials_exception
# 这里可以添加从数据库获取用户信息的逻辑
return username
2. 保护路由
使用Depends
依赖项来保护需要鉴权的路由。
@app.get("/users/me")
async def read_users_me(current_user: str = Depends(get_current_user)):
return {"username": current_user}
3. 设置不鉴权的接口
对于不需要鉴权的接口,你可以直接定义它们而不使用Depends
依赖项。
@app.get("/public")
async def read_public():
return {"message": "这是公开信息,不需要鉴权"}
4. 登录接口
创建一个登录接口来生成Token。
from datetime import datetime, timedelta
# 生成Token的函数
def create_access_token(data: dict, expires_delta: 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
@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
user = authenticate_user(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.username}, expires_delta=access_token_expires
)
return {"access_token": access_token, "token_type": "bearer"}
5. 综合示例
from fastapi import FastAPI
from fastapi.security import OAuth2PasswordBearer
from jose import jwt, JWTError
app = FastAPI()
SECRET_KEY = "your_secret_key"
ALGORITHM = "HS256"
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")
def authenticate_user(username: str, password: str):
# 这里应该添加从数据库验证用户的逻辑
if username == "admin" and password == "password":
return username
return False
def create_access_token(data: dict, expires_delta: 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
except JWTError:
raise credentials_exception
# 这里可以添加从数据库获取用户信息的逻辑
return username
@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
user = authenticate_user(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=30)
access_token = create_access_token(
data={"sub": user.username}, expires_delta=access_token_expires
)
return {"access_token": access_token, "token_type": "bearer"}
@app.get("/users/me")
async def read_users_me(current_user: str = Depends(get_current_user)):
return {"username": current_user}
@app.get("/public")
async def read_public():
return {"message": "这是公开信息,不需要鉴权"}
在这个示例中,/users/me
接口需要鉴权,而/public
接口不需要鉴权。通过这种方式,你可以灵活地控制FastAPI应用中的鉴权逻辑。
学习Python是一个循序渐进的过程,以下是一些关键点,可以帮助你总结和巩固Python的学习:
-
基础语法:
- 掌握变量、数据类型(如整数、浮点数、字符串、列表、元组、字典等)。
- 理解控制流(if语句、for循环、while循环)。
- 学习函数的定义和调用,以及如何传递参数。
-
面向对象编程:
- 理解类和对象的概念,以及如何定义类和实例化对象。
- 学习类的属性和方法,以及如何实现继承、封装和多态。
-
模块和包:
- 了解如何导入和使用Python标准库中的模块。
- 学习如何创建自定义模块和包,以及如何管理项目依赖。
-
异常处理:
- 掌握try-except语句的使用,以及如何自定义异常。
-
文件操作:
- 学习如何打开、读取、写入和关闭文件。
- 理解文件路径和目录操作。
-
数据处理和分析:
- 掌握列表推导式、生成器表达式和迭代器的使用。
- 学习使用
pandas
库进行数据分析和处理。
-
网络编程:
- 学习如何使用
requests
库进行HTTP请求。 - 理解网络协议的基础知识,如HTTP和TCP/IP。
- 学习如何使用
-
Web开发:
- 学习使用Flask或Django框架进行Web应用开发。
- 理解RESTful API的概念和实现。
-
数据库操作:
- 学习如何使用
sqlite3
或SQLAlchemy
进行数据库操作。 - 理解SQL语言的基础知识。
- 学习如何使用
-
测试和调试:
- 学习使用
unittest
框架进行单元测试。 - 掌握使用调试工具,如
pdb
。
- 学习使用
-
代码风格和最佳实践:
- 遵循PEP 8代码风格指南。
- 学习编写可读性高、可维护的代码。
-
高级特性:
- 学习装饰器的使用。
- 理解上下文管理器和
with
语句。 - 学习异步编程和多线程/多进程。
-
项目实践:
- 通过实际项目应用所学知识。
- 学习版本控制工具,如Git。
-
持续学习:
- 随着Python和相关技术的不断发展,持续学习新的库和框架。
- 参与开源项目,与其他开发者交流。
每个学习阶段都有其重点,但最重要的是实践。通过编写代码、解决实际问题和构建项目,你可以更好地理解和掌握Python。此外,阅读他人的代码、参与编程社区讨论和学习最佳实践也是提高编程技能的有效途径。