26.FastAPI安全性
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了26.FastAPI安全性相关的知识,希望对你有一定的参考价值。
参考技术A 软件开发中,安全是永恒的话题,FastAPI作为一个优秀的Python Web开发框架,为用户提供了多种工具,帮助用户以标准的方式轻松快速地解决软件开发中的安全性。FastAPI 的 fastapi.security 模块中为各种安全方案提供了一些工具,这些工具简化了这些安全机制的使用方法。
FastAPI提供的OAuth2PasswordBearer是使用 OAuth2的密码授权模式的Bearer Token(不记名 token) 。创建OAuth2PasswordBearer 实例需要接收URL作为参数。
客户端会向该 URL 通过表单的格式发送 username 和 password 参数,然后得到一个 token 值;OAuth2PasswordBearer 并不会创建相应的 URL 路径操作,只是指明了客户端用来获取 token 的目标 URL。
代码示例:
在上面的代码中, tokenUrl="token"指的token是相对 URL 。
此时访问,其返回结果:
上面的结果表明:访问的内容以及被保护,必须经过授权后才可以访问。
当获取到表单数据后,需要进行密码校验,一般情况下,我们都会考虑使用哈希密码,PassLib 是一个用于处理哈希密码的非常好的 Python 包,它支持许多安全哈希算法以及配合算法使用的实用程序。
具体passlib的使用方法可以查看其文档https://passlib.readthedocs.io/en/stable
下面的代码示例在上面代码的基础上增加用户登录及Token验证
启动应用并执行请求:
测试无效登录:
测试正常登录:
返回token,在Headers中使用token访问:
修改token后请求:
上面的代码如果去掉 await verify_token(token) 行,则:
curl -H "Authorization:Bearer u000010007" http://127.0.0.1:8000 -i
会得到返回结果,原因是默认情况下,OAuth2PasswordBearer只负责请求头中是否具有Authorization:Bearer,如果有就会执行相应的请求,所以,为了验证Token的正确性,需要每个方法都执行相应的验证代码。
本例只作为例子,在实际开发中不会直接拿用户ID作为Token,为了提高系统的安全性,需要使用 JWT。下面我们就介绍 JWT。
JWT是一个将 JSON 对象编码为密集且没有空格的长字符串的标准。 具体学习和了解 JWT,请参考 https://jwt.io。
需要提到的主要是 JWT中的sub,JWT 的规范中有一个 sub 键,值为该令牌的主题。使用它并不是必须的,但这是我们放置用户标识的地方,所以一般情况下,我们在sub中存放用户ID, 为了避免 ID 冲突,当为创建 JWT 令牌时,可以在 sub 键的值前加上前缀,例如 username:、userid:等。
在 Python 中生成和校验 JWT 令牌 ,可以使用PyJWT,也可以使用 python-jose 。我们在本例中使用 python-jose 来编写代码。
使用:
使用 JWT,需要在系统中添加一个SECRET_KEY变量,用于生成令牌,如:
以下代码在上面代码的基础上使用 JWT 令牌。
与前面的代码差别之处:
1.生成Token的函数:build_access_token
2.校验Token的函数:verify_token
3.登录函数:login
请求测试:
登录:
令牌访问:
错误的令牌访问:
在大部分应用程序中,当用户访问某个接口API的时候,都需要明确访问者的身份,所以在应用程序中需要随时获取当前用户,由于在 JWT 令牌的 sub 字段中已经保存了用户信息,所以获取当前用户只需要对令牌解码即可。
在上面的代码的基础上,增加两个函数,代码如下:
请求测试:
以上,我们完成了一个简单的安全性示例,FastAPI提供的安全性框架帮助我们节约了很多代码,但在实际开发中,我们常常使用微服务的方式来开发,对于鉴权最好设计独立的微服务进行处理。后面我们会展示一个采用FastAPI开发的鉴权微服务,以便在此基础上进行业务系统的开发。
FastAPI 学习之路请求体有多个参数如何处理?
系列文章:
FastAPI 学习之路(一)fastapi--高性能web开发框架
请求体有多个参数如何处理?
别的不多说,我们先写一个需求,然后演示下如何展示。
需求:写一个接口,传递以下参数,书本的名称,描述,价格,打折。
接口返回返回最后的价格
我们去看下代码如何实现
from typing import Optional from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() class Item(BaseModel): name: str description: Optional[str] = None price: float tax: Optional[float] = None @app.put("/items") def update_item(item: Optional[Item]): result={} if item.tax is not None: total=item.price*item.tax result[\'price\'] = total result[\'name\']=item.name return result result[\'price\'] = item.price result[\'name\'] = item.name return result
那么我们测试下,最后是否实现了这个功能,当我们输入所有的参数的时候。
最后是在我们实际的打折上返回的。
那么我们看下,我们不增加打折如何返回
没有打折就原价返回了名称和价格。
如果默认给了None或者其他内容,这个参数就是可以选择增加或者不增加。但是没有给默认值的时候,就是必须传递的,否则会返回对应的错误,我们可以看下。假如我们不传递价格。
我们可以看到没有默认值的参数就是一个必须的。不然接口会返回对应的错误。
除了声明以上单个的,我们还可以声明多个请求体参数,比如我们可以在之前的需求,增加一个返回,要求返回作者,和作者的朝代。如何实现呢。
from typing import Optional from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() class Item(BaseModel): name: str description: Optional[str] = None price: float tax: Optional[float] = None class User(BaseModel): username: str year: str @app.put("/items") async def update_item(item: Optional[Item],user:User): result={} if item.tax is not None: total=item.price*item.tax result[\'price\'] = total result[\'name\']=item.name result[\'user\']=user return result result[\'price\'] = item.price result[\'name\'] = item.name result[\'user\']=user return result
那么我们看下接口的请求
当我们增加打折。看下返回结果
我们可以看下接口的返回。
FastAPI 将自动对请求中的数据进行转换,因此 item 参数将接收指定的内容,user 参数也是如此。
我们要想在增加一个键,在哪里出售,但是要作为请求体的另一个键进行处理,如何 实现呢
from typing import Optional from fastapi import FastAPI,Body from pydantic import BaseModel app = FastAPI() class Item(BaseModel): name: str description: Optional[str] = None price: float tax: Optional[float] = None class User(BaseModel): username: str year: str @app.put("/items") async def update_item(item: Optional[Item],user:User,sell:str=Body(...)): result={} if item.tax is not None: total=item.price*item.tax result[\'price\'] = total result[\'name\']=item.name result[\'user\']=user result[\'sell\']=sell return result result[\'price\'] = item.price result[\'name\'] = item.name result[\'user\']=user result[\'sell\'] = sell return result
我们可以看到如下
假如我们把参数放在查询内,返回错误
参数必须放在body内请求。
文章首发在公众号,欢迎关注。
以上是关于26.FastAPI安全性的主要内容,如果未能解决你的问题,请参考以下文章