赞
踩
安全介绍
有许多方式去处理安全性,身份认证和授权。
并且它通常是一个复杂而又困难的话题。
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定义了以下安全方案:
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以及授权。
因此,让我们从简化的角度进行回顾:
它将会去请求得头部中查找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内容的类依赖:
OAuth2PasswordBearer 使fastapi知道他是安全模式,所以它会被直接加到openapi中,而OAuth2PasswordRequestForm仅仅是一个类依赖,你也可以直接自己声明表单参数。fastapi提供它仅仅是使用起来更简单。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。