安全介绍
有许多方式去处理安全性,身份认证和授权。
并且它通常是一个复杂而又困难的话题。
fastapi提供一些工具去更容易的处理安全问题。
先来了解一些小的概念
1、OAuth2
OAuth2是一个规范,定义了几种处理身份验证和授权的方式。
它是一个相当广泛的规范,涵盖了几个复杂的用例。
它包括使用“第三方”进行身份验证的方法。
这就是所有带有“使用Facebook,Google,Twitter,GitHub登录”的系统的基础
2、OAuth 1
有一个OAuth 1,它与OAuth2完全不同,并且更为复杂,因为它直接包含有关如何加密通信的规范。
它现在不是很流行或使用。
OAuth2没有指定如何加密通信,它希望您使用HTTPS为您的应用程序提供服务
3、OpenID
OpenID Connect是另一个基于OAuth2的规范。
它只是扩展了OAuth2,以指定一些在OAuth2中相对模糊的内容,以尝试使其更具互操作性。
例如,Google登录使用OpenID Connect(在下面使用OAuth2)。
但是,Facebook登录不支持OpenID Connect。它具有自己的OAuth2风格。
4、OpenAPI
OpenAPI(以前称为Swagger)是用于构建API(现已成为Linux Foundation的一部分)的开放规范。
FastAPI基于OpenAPI。
这就是使多个自动交互式文档界面,代码生成等成为可能的原因。
OpenAPI具有定义多个安全“方案”的方法。
通过使用它们,您可以利用所有这些基于标准的工具,包括这些交互式文档系统。
OpenAPI定义了以下安全方案:
- apiKey:特定于应用程序的密钥,可以来自:
- 查询参数。
- header。
- cookie。
- http:标准的HTTP身份验证系统,包括:
- bearer:标题Authorization的值Bearer加上令牌。这是从OAuth2继承的。
- HTTP基本身份验证。
- HTTP摘要等
- oauth2:所有OAuth2处理安全性的方式(称为“流程”)。
- 其中一些流程适合构建OAuth 2.0身份验证提供程序(例如Google,Facebook,Twitter,GitHub等):
- implicit
- clientCredentials
- authorizationCode
- 但是,有一个特定的“流”可以完美地用于直接在同一应用程序中处理身份验证:
- password:接下来的几章将介绍此示例。
- 其中一些流程适合构建OAuth 2.0身份验证提供程序(例如Google,Facebook,Twitter,GitHub等):
- openIdConnect:具有定义自动发现OAuth2身份验证数据的方式。 此自动发现是OpenID Connect规范中定义的内容。
fastapi utilities
fastapi提供一些工具给以上的安全模式在fastapi.security模块中。
第一步
想象一下你的后端api在一个域中,而你的前端在另一个域中,或者在相同域中的不同的路径。
并且你想通过用户名和密码来进行前后端授权。
可以使用OAuth2来构建fastapi。
首先来看看它是怎么工作的。
from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordBearer
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")
@app.get("/items/")
async def read_items(token: str = Depends(oauth2_scheme)):
return {"token": token}
要想让它运行得先安装python-multipart。这是因为OAuth2使用表单数据来发送用户名密码。
运行后可以直接在docs中进行测试。

目前你无论填入什么都将不起作用。
password flow
密码流是OAuth2中定义得流中得一种方式,去处理安全以及身份验证。
OAuth2被设计来已确保后端或api能够独立于授权用户得服务。
但是这个例子中fastpi程序将会处理api以及授权。
因此,让我们从简化的角度进行回顾:
- 用户在前端键入他username和和password,然后点击Enter。
- 前端(在用户的浏览器中运行)发送一个username和password我们的API在一个特定的URL。
- API会检查username和password,并以“令牌”作为响应
- 令牌”只是一个包含一些内容的字符串,我们稍后可以使用它来验证该用户。
- 通常,令牌设置为在一段时间后过期。
- 因此,用户稍后将不得不再次登录。
- 而且,如果令牌被盗,则风险会降低。它不像将永远有效的永久密钥(在大多数情况下)。
- 前端将该令牌临时存储在某个地方。
- 用户单击前端以转到前端Web应用程序的另一部分。
- 前端需要从API中获取更多数据。
- 但是它需要针对该特定端点的身份验证。
- 因此,为了通过我们的API进行身份验证,它会发送一个标头Authorization,其值Bearer加上令牌。
- 如果令牌包含foobar,则Authorization标头的内容为:Bearer foobar。
OAuth2PasswordBearer
OAuth2PasswordBearer是fastapi提供得使用Bearer token得password流。
它是客户端使用username 和password来发送并获得token得类。
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")
它并不创建端点路径操作,但是声明客户端得到token得地址。
然后使用实例作为路径操作得依赖,这个依赖返回得参数是一个str类型得token。
它将会去请求得头部中查找Authorization,验证值是否是Bearer+token并且返回token。
如果头部中没有Authorization,或者值不包括Bearer token,将会返回401.
甚至不用你去检查token是否存在,你可以很确定只要函数被执行了,就能够得到token。
得到当前用户
首先创建用户模型,
class User(BaseModel):
username: str
email: Optional[str] = None
full_name: Optional[str] = None
disabled: Optional[bool] = None
创建get_current_user 依赖
get_current_user将会依赖oauth2_scheme。并从中得到token。
async def get_current_user(token: str = Depends(oauth2_scheme)):
user = fake_decode_token(token)
return user
get_current_user将会使用一个假的功能函数,以token作为参数并返回user模型。
def fake_decode_token(token):
return User(
username=token + "fakedecoded", email="john@example.com", full_name="John Doe"
)
完整代码:
from typing import Optional
from fastapi import Depends, FastAPI
from fastapi.security import OAuth2PasswordBearer
from pydantic import BaseModel
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")
class User(BaseModel):
username: str
email: Optional[str] = None
full_name: Optional[str] = None
disabled: Optional[bool] = None
def fake_decode_token(token):
return User(
username=token + "fakedecoded", email="john@example.com", full_name="John Doe"
)
async def get_current_user(token: str = Depends(oauth2_scheme)):
user = fake_decode_token(token)
return user
@app.get("/users/me")
async def read_users_me(current_user: User = Depends(get_current_user)):
return current_user
在登陆的路径操作中需要以form格式传入username以及password
scope
客户端还可以传入scope参数,这个参数实际是以空格分隔的多个scope。每一个scope都是string。
他们经常被用于声明特殊的安全权限,eg:
users:read or users:write
OAuth2PasswordRequestForm
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from pydantic import BaseModel
fake_users_db = {
"johndoe": {
"username": "johndoe",
"full_name": "John Doe",
"email": "johndoe@example.com",
"hashed_password": "fakehashedsecret",
"disabled": False,
},
"alice": {
"username": "alice",
"full_name": "Alice Wonderson",
"email": "alice@example.com",
"hashed_password": "fakehashedsecret2",
"disabled": True,
},
}
app = FastAPI()
def fake_hash_password(password: str):
return "fakehashed" + password
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")
class User(BaseModel):
username: str
email: str = None
full_name: str = None
disabled: bool = None
class UserInDB(User):
hashed_password: str
def get_user(db, username: str):
if username in db:
user_dict = db[username]
return UserInDB(**user_dict)
def fake_decode_token(token):
# This doesn't provide any security at all
# Check the next version
user = get_user(fake_users_db, token)
return user
async def get_current_user(token: str = Depends(oauth2_scheme)):
user = fake_decode_token(token)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication credentials",
headers={"WWW-Authenticate": "Bearer"},
)
return user
async def get_current_active_user(current_user: User = Depends(get_current_user)):
if current_user.disabled:
raise HTTPException(status_code=400, detail="Inactive user")
return current_user
@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
user_dict = fake_users_db.get(form_data.username)
if not user_dict:
raise HTTPException(status_code=400, detail="Incorrect username or password")
user = UserInDB(**user_dict)
hashed_password = fake_hash_password(form_data.password)
if not hashed_password == user.hashed_password:
raise HTTPException(status_code=400, detail="Incorrect username or password")
return {"access_token": user.username, "token_type": "bearer"}
@app.get("/users/me")
async def read_users_me(current_user: User = Depends(get_current_active_user)):
return current_user
OAuth2PasswordRequestForm是一个声明以下body内容的类依赖:
- username
- password
- 可选scope
- 可选grant_type
- 可选client_id
- 可选client_secret
OAuth2PasswordBearer 使fastapi知道他是安全模式,所以它会被直接加到openapi中,而OAuth2PasswordRequestForm仅仅是一个类依赖,你也可以直接自己声明表单参数。fastapi提供它仅仅是使用起来更简单。
本文深入探讨FastAPI中的安全性和OAuth2应用,讲解如何使用OAuth2PasswordBearer和OAuth2PasswordRequestForm处理身份验证和授权,包括实现密码流、获取当前用户及验证活跃状态。
811

被折叠的 条评论
为什么被折叠?



