基于Starlette的ASGI应用程序和框架的认证后端和助手
项目描述
starlette-auth-toolkit
Starlette-based ASGI应用程序和框架的认证后端和助手。
注意:文档正在编写中。在此期间,您可以自由地 阅读源代码。
功能
- 数据库无关。
- 用户模型无关。
- 支持密码哈希和哈希迁移。
- 内置对常见认证流程的支持,包括基本和令牌认证。
- 支持多个认证后端。
- 轻松集成到
orm
。
内容
安装
pip install starlette-auth-toolkit
快速入门
import typing
from starlette.applications import Starlette
from starlette.authentication import requires
from starlette.middleware.authentication import AuthenticationMiddleware
from starlette.responses import JSONResponse, PlainTextResponse
from starlette_auth_toolkit.base.backends import BaseBasicAuth
from starlette_auth_toolkit.cryptography import PBKDF2Hasher
# Password hasher
hasher = PBKDF2Hasher()
# Example user model
class User(typing.NamedTuple):
username: str
password: str
# Fake user storage
USERS = {
"alice": User(username="alice", password=hasher.make_sync("alicepwd")),
"bob": User(username="bob", password=hasher.make_sync("bobpwd")),
}
# Authentication backend
class BasicAuth(BaseBasicAuth):
async def find_user(self, username: str):
return USERS.get(username)
async def verify_password(self, user: User, password: str):
return await hasher.verify(password, user.password)
# Application
app = Starlette()
app.add_middleware(
AuthenticationMiddleware,
backend=BasicAuth(),
on_error=lambda _, exc: PlainTextResponse(str(exc), status_code=401),
)
@app.route("/protected")
@requires("authenticated")
async def protected(request):
return JSONResponse({"message": f"Hello, {request.user.username}!"})
将此文件保存为 app.py
。然后,假设您已安装 uvicorn,请运行 $ uvicorn app:app
并发出请求
- 匿名请求
curl -i http://localhost:8000/protected
HTTP/1.1 403 Forbidden
date: Tue, 23 Jul 2019 20:44:52 GMT
server: uvicorn
content-length: 9
content-type: text/plain; charset=utf-8
Forbidden
- 认证请求
curl -i -u alice:alicepwd http://localhost:8000/protected
HTTP/1.1 200 OK
date: Tue, 23 Jul 2019 20:45:24 GMT
server: uvicorn
content-length: 27
content-type: application/json
{"message":"Hello, alice!"}
对于实际示例,请参见 此处。
依赖项
与Starlette一样,starlette-auth-toolkit
没有任何硬依赖,但您可以选择安装以下内容
passlib
- 如果您想使用密码哈希器,则必需。
基本后端
基本后端实现了一个 认证流程,但凭据验证的确切实现留给了您。这意味着您可以选择执行数据库查询、使用环境变量或私有文件等。
这些后端在认证成功时授予一组 作用域。
尽管基本后端与用户模型无关,但我们建议您实现由 starlette.authentication.BaseUser
指定的接口(也请参阅 Starlette 认证)。
它们位于 starlette_auth_toolkit.base.backends
。
BaseBasicAuth
基本实现 基本认证方案。
请求头格式
Authorization: Basic {credentials}
其中 {credentials}
指的是 {username}:{password}
的 base64 编码。
示例
# myapp/auth.py
from starlette.authentication import SimpleUser # or a custom user model
from starlette_auth_toolkit.base.backends import BaseBasicAuth
class BasicAuth(BaseBasicAuth):
async def verify(self, username: str, password: str):
# In practice, request the database to find the user associated
# to `username`, and validate that its password hash matches the
# given password.
if (username, password) != ("bob", "s3kr3t"):
return None
return SimpleUser(username)
抽象方法
-
async
.verify(self, username: str, password: str) -> Optional[BaseUser]
如果
username
和password
有效,则返回相应的用户。否则,返回None
。
作用域
已认证
BaseTokenAuth
基础实现令牌认证,是 Bearer 认证方案 的简化版。
请求头格式
Authorization: Token {token}
示例
# myapp/auth.py
from starlette.authentication import SimpleUser # or a custom user model
from starlette_auth_toolkit.base.backends import BaseTokenAuth
class TokenAuth(BaseTokenAuth):
async def verify(self, token: str):
# In practice, request the database to find the token object
# associated to `token`, and return its associated user.
if token != "abcd":
return None
return SimpleUser("bob")
抽象方法
-
async
.verify(self, token: str) -> Optional[BaseUser]
如果
token
指的是有效令牌,则返回相应的用户。否则,返回None
。
作用域
已认证
后端
此处列出的认证后端是现成的实现,位于 backends
模块中,除非另有说明。
contrib.orm.ModelBasicAuth
使用 orm
用户模型实现 BaseBasicAuth
的现成实现。
注意:要使用此后端,必须安装 orm
。
示例
from starlette.applications import Starlette
from starlette_auth_toolkit.contrib.orm import ModelBasicAuth
from starlette_auth_toolkit.cryptography import PBKDF2Hasher
from myproject.models import User # DIY
hasher = PBKDF2Hasher()
app = Starlette()
app.add_middleware(
AuthenticationMiddleware,
backend=ModelBasicAuth(User, hasher=hasher)
)
参数
model
(orm.Model
或() -> orm.Model
):用户模型(或用于延迟加载的可调用对象)。hasher
(BaseHasher
):密码哈希器 — 与用于哈希用户密码的相同。password_field
(str
,可选):存储在用户对象上的密码哈希字段。默认为"password"
。
作用域
已认证
多认证
此后端允许您在应用程序中支持多种认证方法。 MultiAuth
将按顺序尝试使用提供的 backends
进行认证,直到成功(或全部失败)。
注意:如果任何后端因 AuthenticationError
失败(例如,因为提供了某些凭据但它们无效),MultiAuth
将传播异常,并且不会进行进一步的尝试 — 即使稍后的后端可能会成功。
示例
from starlette_auth_toolkit.backends import MultiAuth
from myproject.auth import TokenAuth, BasicAuth # TODO
# Allow to authenticate using either a token or username/password credentials.
backend = MultiAuth([TokenAuth(), BasicAuth()])
参数
backends
(List[AuthBackend]
):认证后端列表,确定客户端可以使用哪些认证方法进行认证。
作用域
已认证
密码哈希器
此软件包提供基于 PassLib 构建的密码哈希实用程序。
用法
- 异步:
await .make()
/await .verify()
(哈希和验证在线程池中执行)
import asyncio
from starlette_auth_toolkit.cryptography import PBKDF2Hasher
async def main():
# Instanciate a hasher:
hasher = PBKDF2Hasher()
# Hash a password:
pwd = await hasher.make("hello")
# Verify a password against a known hash:
assert await hasher.verify("hello", pwd)
# Python 3.7+
asyncio.run(main())
- 阻塞:
.make_sync()
/.verify_sync()
from starlette_auth_toolkit.cryptography import PBKDF2Hasher
# Instanciate a hasher:
hasher = PBKDF2Hasher()
# Hash a password
pwd = hasher.make_sync("hello")
# Verify a password against a known hash:
assert hasher.verify_sync("hello", pwd)
哈希迁移(高级)
如果您需要更改哈希算法(例如,从 PBKDF2 更改为 Argon2),您通常希望保留对现有哈希的支持,但尽快使用新算法重新哈希。
MultiHasher
就是为此而设计的
from starlette_auth_toolkit.cryptography import Argon2Hasher, PBKDF2Hasher, MultiHasher
hasher = MultiHasher([Argon2Hasher(), PBKDF2Hasher()])
上述 hasher
在哈希新密码时将使用 Argon2,但将能够验证使用 Argon2 或 PBKDF2 创建的哈希。
要检测是否需要重新哈希,请使用 .needs_update()
valid = await hasher.verify(pwd, pwd_hash)
if hasher.needs_update(pwd_hash):
new_hash = await hasher.make(pwd)
# TODO: store new hash
# ...
注意:在调用
.verify()
之外的时间调用.needs_update()
将引发RuntimeError
。
可用的哈希器
名称 | 需要 | PassLib 算法 |
---|---|---|
PBKDF2Hasher |
pbkdf2_sha256 |
|
CryptHasher |
sha256_crypt |
|
BCryptHasher |
bcrypt |
bcrypt |
Argon2Hasher |
argon2-cffi |
argon2 |
MultiHasher |
N/A |
对于高级用例,请使用 Hasher
并传递 passlib.hash 中列出的其中一个算法。
from starlette_auth_toolkit.cryptography import Hasher
hasher = Hasher(algorithm="pbkdf2_sha512")
在视图中认证
如果您需要在视图中对用户进行认证,即用一对 username
和 password
交换实际的 user
,请使用您的 BasicAuth
后端。
auth = MyBasicAuth()
@app.route("/guard")
async def logs_user_in(request):
data = await request.json()
username = data["username"]
password = data["password"]
user = await auth.verify(username, password)
# ...
贡献
想要贡献?太棒了!请务必阅读我们的贡献指南。
变更日志
查看CHANGELOG.md。
许可
MIT
项目详情
下载文件
下载适用于您平台的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。
源代码分发
构建分发
starlette-auth-toolkit-0.5.0.tar.gz的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 9fd041aff89fffe67feb8cd94e10e2a8bbf609aeb6a736a74fce79320254e1f1 |
|
MD5 | d765eb9639aa96b416bc03d0b8fcbdcd |
|
BLAKE2b-256 | 74a2d414932fc33b56dff74fa34f4b37f4d3ceedbaf863dacea85d7eee113ce7 |
starlette_auth_toolkit-0.5.0-py3-none-any.whl的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 5b3b651bf05d3f0332846fac52b7266b06f05d9264c7a9d065ca51dccf765a7a |
|
MD5 | d400a73074bd05444fe8ae91f42b05bc |
|
BLAKE2b-256 | 2470c5d1971ed20d21a78223af79ca7889d715dcb59af628fea9228e79383bc9 |