Python 后端 | FastAPI文档解读 | 安全性

来源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。安装命令:pip install python-multipart。这是因为 OAuth2 使用表单数据发送 username 与 password。

代码说明

补充知识:形如def function1 (param: = Depends(function2))function2为依赖项,具体来说,调用function1时,function1读取function2需要的实参给function2,然后function2执行结果返回给parm,更具体可参考依赖项官方文档

从路径函数入手,async def read_items(token: str = Depends(oauth2_scheme)):,其中oauth2_schemeOAuth2PasswordBearer的实例化对象(可调用对象),作为依赖项oauth2_scheme读取请求头中Authorization内容,获取形式如{'access_token':..., 'token_type':...}的字典内容。而显然不做任何操作现在请求头中是不会有任何内容的。
所以样例代码运行结果为下图,显示没有权限。

在这里插入图片描述

我们会注意到文档页面多了一个东西Authorize。

在这里插入图片描述
在这里插入图片描述

这个是由于使用了OAuth2PasswordBearer依赖项。它会调用tokenUrl初始化时传入的实参比如'token',调用该路径函数,并将结果返回作为请求头的Authorization。如果将代码改成,#ADD注释为增加到代码。

import uvicorn
from fastapi import FastAPI, Depends
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}
@app.post("/token")    # ADD
async def create_token():   # ADD
    return {"access_token": "111", "token_type": "bearer"}  #ADD

验证完后,发起的请求如下。
在这里插入图片描述

实践指导

所以OAuth2PasswordBearer功能如下:

  1. 读取头文件的Authorization
  2. 验证Authorization符不符合规定。
  3. 返回access_token字段
    所以在Fastapi中

获取当前用户

原文

示例代码

from typing import Union

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: Union[str, None] = None
    full_name: Union[str, None] = None
    disabled: Union[bool, None] = 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
    

代码说明

到目前为止,还没有涉及到登录的实际意义,这里可以直接跳过。

实践指导

使用密码和 Bearer 的简单 OAuth2

原文

示例代码

from typing import Union

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: Union[str, None] = None
    full_name: Union[str, None] = None
    disabled: Union[bool, None] = 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

代码说明

token路径函数给前端赋予token。调用了OAuth2PasswordBearer依赖项的为解释token的过程,一般解释过程就是寻找到对应的用户。
所以整体上来说,上面代码中get_current_active_user以上都为获得前端传过来的token之后的验证解释token过程,而token路径函数为验证用户名密码,并赋予token的过程。到目前为止还是没有安全性可言,因为我们传出去的token是数据库中存在的用户,而验证token也是直接匹配用户名,所以实际上不进行token的获取,而直接在请求头的Authorization传入用户名就可以登录。
更具体上来看,token路径函数验证了用户名和相应的哈希密码,get_current_active_user函数根据数据库字段判断用户是否可用,get_current_user函数获取token,fake_decode_token解释token,

实践指导

在这里插入图片描述

OAuth2 实现密码哈希与 Bearer JWT 令牌验证

原文
可直接看原文
这里才具有安全性

实践指导

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FastAPI中进行跨域配置可以使用fastapi.middleware.CORSMiddleware中间件。以下是一个示例: ```python from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware app = FastAPI() # 允许所有来源的跨域请求 app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) ``` 在上述示例中,我们导入了FastAPI和CORSMiddleware,然后创建了一个FastAPI应用程序对象`app`。 接下来,通过调用`add_middleware`方法添加了CORSMiddleware中间件。这个中间件允许了所有来源的跨域请求。你可以根据需要修改`allow_origins`、`allow_credentials`、`allow_methods`和`allow_headers`参数来设置更详细的跨域配置。 - `allow_origins`:允许访问的来源,可以是一个字符串列表,如`["http://localhost:8080", "http://example.com"]`,或者使用通配符`"*"`允许所有来源。 - `allow_credentials`:是否允许发送身份验证凭证(如cookie)。 - `allow_methods`:允许的请求方法,可以是一个字符串列表,如`["GET", "POST", "PUT", "DELETE"]`,或者使用通配符`"*"`允许所有方法。 - `allow_headers`:允许的请求头部字段,可以是一个字符串列表,如`["Content-Type", "Authorization"]`,或者使用通配符`"*"`允许所有字段。 请注意,上述示例只是一个简单的示例,你可能需要根据实际情况进行调整和扩展。希望对你有帮助!如果还有其他问题,请继续提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值