Skip to main content

No project description provided

Project description

FastAPI-Pydentity

Installation

First you have to install fastapi-pydentity like this:

pip install fastapi-pydentity

You can also install with your db adapter:

For SQLAlchemy:

pip install fastapi-pydentity[sqlalchemy]

For Tortoise ORM:

pip install fastapi-pydentity[tortoise]

Example

from typing import Annotated

from fastapi import Depends, HTTPException
from pydenticore import SignInManager, UserManager, RoleManager

from examples.app import app
from examples.models import User
from examples.schemes import RegisterInputModel, LoginInputModel
from examples.stores import UserStore, RoleStore
from fastapi_pydentity import PydentityBuilder
from fastapi_pydentity.authentication import use_authentication
from fastapi_pydentity.authorization import use_authorization, Authorize

builder = PydentityBuilder()
builder.add_default_identity(UserStore, RoleStore)
builder.add_authorization()
builder.build()

use_authentication(app)
use_authorization(app)


@app.post("/register")
async def register(
        model: Annotated[RegisterInputModel, Depends()],
        user_manager: Annotated[UserManager, Depends()],
        signin_manager: Annotated[SignInManager, Depends()],
):
    if model.password.get_secret_value() != model.confirm_password.get_secret_value():
        raise HTTPException(status_code=400, detail=["Passwords don't match."])

    user = User(email=model.email, username=model.email)
    result = await user_manager.create(user, model.password.get_secret_value())

    if result.succeeded:
        await signin_manager.sign_in(user, is_persistent=False)
    else:
        raise HTTPException(status_code=400, detail=[err.description for err in result.errors])


@app.post("/register-admin")
async def register_admin(user_manager: Annotated[UserManager, Depends()], ):
    user = User(email="admin@example.com", username="admin@example.com")
    result = await user_manager.create(user, "P@ssw0rd")

    if not result.succeeded:
        raise HTTPException(status_code=400, detail=[err.description for err in result.errors])

    await user_manager.add_to_roles(user, "admin")


@app.post("/login")
async def login(model: Annotated[LoginInputModel, Depends()], signin_manager: Annotated[SignInManager, Depends()], ):
    result = await signin_manager.password_sign_in(
        model.email,
        model.password.get_secret_value(),
        model.remember_me
    )

    if not result.succeeded:
        raise HTTPException(status_code=401, detail="Invalid login attempt.")


@app.post("/logout", dependencies=[Authorize()])
async def logout(signin_manager: Annotated[SignInManager, Depends()], ):
    await signin_manager.sign_out()


@app.get("/users", dependencies=[Authorize()])
async def get_users(user_manager: Annotated[UserManager, Depends()], ):
    return [user.email for user in await user_manager.all()]


@app.get("/roles", dependencies=[Authorize("admin")])
async def get_roles(role_manager: Annotated[RoleManager, Depends()], ):
    return [role.name for role in await role_manager.all()]


if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app)

Configure identity options

from pydenticore import IdentityOptions

from examples.stores import UserStore, RoleStore
from fastapi_pydentity import PydentityBuilder


def configure_options(options: IdentityOptions):
    options.signin.required_confirmed_account = False
    options.password.required_unique_chars = 4
    options.password.required_length = 12


builder = PydentityBuilder()
builder.add_default_identity(UserStore, RoleStore).configure_options(configure_options)
# builder.add_identity(UserStore, RoleStore, configure_options)

Authentication

Cookie

from typing import Annotated

from fastapi import Depends, HTTPException
from pydenticore import SignInManager

from examples.app import app
from examples.schemes import LoginInputModel
from examples.stores import UserStore, RoleStore
from fastapi_pydentity import PydentityBuilder
from fastapi_pydentity.authentication import use_authentication
from fastapi_pydentity.authorization import use_authorization

builder = PydentityBuilder()
builder.add_default_identity(UserStore, RoleStore)
builder.add_authorization()
builder.build()

use_authentication(app)
use_authorization(app)


@app.post("/login")
async def login(model: Annotated[LoginInputModel, Depends()], signin_manager: Annotated[SignInManager, Depends()], ):
    result = await signin_manager.password_sign_in(
        model.email,
        model.password.get_secret_value(),
        model.remember_me
    )

    if not result.succeeded:
        raise HTTPException(status_code=401, detail="Invalid login attempt.")

JWT Bearer

from typing import Annotated

from fastapi import Depends, HTTPException
from pydenticore import SignInManager

from examples.app import app
from examples.schemes import LoginInputModel
from examples.stores import UserStore, RoleStore
from fastapi_pydentity import PydentityBuilder
from fastapi_pydentity.authentication import use_authentication
from fastapi_pydentity.authentication.bearer import TokenValidationParameters, JWTSecurityToken
from fastapi_pydentity.authorization import use_authorization

builder = PydentityBuilder()
builder.add_default_identity(UserStore, RoleStore)
builder.add_authentication("Bearer").add_jwt_bearer(
    validation_parameters=TokenValidationParameters(
        issuer_signing_key="<SECRETKEY>",
        valid_algorithms=["HS256"],
    )
)
builder.add_authorization()
builder.build()

use_authentication(app)
use_authorization(app)


@app.post("/login")
async def login(model: Annotated[LoginInputModel, Depends()], signin_manager: Annotated[SignInManager, Depends()], ):
    user = await signin_manager.user_manager.find_by_email(model.email)
    result = await signin_manager.check_password_sign_in(
        user,
        model.password.get_secret_value(),
        model.remember_me
    )

    if result.succeeded:
        principal = await signin_manager.create_user_principal(user)
        token = JWTSecurityToken(
            signin_key="<SECRETKEY>",
            claims=principal.claims,
        )
        return {"access_token": token.encode()}

    raise HTTPException(status_code=401, detail="Invalid login attempt.")

Configure policy

First we add the policies:

from pydenticore.authorization import AuthorizationPolicyBuilder

from examples.app import app
from fastapi_pydentity import PydentityBuilder
from fastapi_pydentity.authentication import use_authentication
from fastapi_pydentity.authorization import use_authorization

location_policy_builder = AuthorizationPolicyBuilder("LocationPolicy")
location_policy_builder.require_claim("location", "London")
location_policy = location_policy_builder.build()

builder = PydentityBuilder()
builder.add_authorization().add_policy("LocationPolicy", location_policy)
# authorization_builder = builder.add_authorization()
# authorization_builder += location_policy
builder.build()

use_authentication(app)
use_authorization(app)

After that, they can be used in the route:

from fastapi import APIRouter

from fastapi_pydentity.authorization import Authorize

router = APIRouter(prefix="/secure")


@router.get("/data-1", dependencies=[Authorize(policy="LocationPolicy")])
async def get_secure_data():
    return "This is protected data-1."


@router.get("/data-2", dependencies=[Authorize(policy="LocationPolicy")])
async def get_secure_data():
    return "This is protected data-2."

or in APIRouter:

from fastapi import APIRouter

from fastapi_pydentity.authorization import Authorize

router = APIRouter(prefix="/secure", dependencies=[Authorize(policy="LocationPolicy")])


@router.get("/data-1")
async def get_secure_data():
    return "This is protected data-1."


@router.get("/data-2")
async def get_secure_data():
    return "This is protected data-2."

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fastapi_pydentity-0.1.2.tar.gz (27.5 kB view details)

Uploaded Source

Built Distribution

fastapi_pydentity-0.1.2-py3-none-any.whl (14.8 kB view details)

Uploaded Python 3

File details

Details for the file fastapi_pydentity-0.1.2.tar.gz.

File metadata

  • Download URL: fastapi_pydentity-0.1.2.tar.gz
  • Upload date:
  • Size: 27.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.3 CPython/3.12.2 Windows/11

File hashes

Hashes for fastapi_pydentity-0.1.2.tar.gz
Algorithm Hash digest
SHA256 20a574d8753b6f3515cd43e01b57253cd4c2599447fa5cbb19b115bd9db528f0
MD5 827551dc3395468befdbf72269656111
BLAKE2b-256 da13f7c10b46c52fbd28b214010136b09b5e62ec2887e4515c586bc6654e3ff5

See more details on using hashes here.

File details

Details for the file fastapi_pydentity-0.1.2-py3-none-any.whl.

File metadata

File hashes

Hashes for fastapi_pydentity-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 5752a5e048ebbb8b5eb4e166a4e4da089d710e3b277103fb75c6f069f873ec9d
MD5 270a36bfa9b727223ebc24ea40e1a639
BLAKE2b-256 fff586718b7d8edeeaf98826d09f9def59d6adf659af8dad95e34b17713fd71f

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page