Files
François Voron 373157c284 Finalize user activation feature (#439)
* Add routes for user activation (#403)

* Add routes for user activation

Generate a token after creating the user in register route, passing to `activation_callback`, if `activation_callback` supplied
Create new `/activate` route that will verify the token and activate the user
Add new error codes to `fastapi_users/router/common.py`
Update documentation
Add tests

Co-authored-by: Mark Todd <markpeter.todd@hotmail.co.uk>

* Rework routes for user activation

* Separate verification logic and token generation into `/fastapi_users/router/verify.py`, with per-route callbacks for custom behaviour

* Return register router to original state

* Added `is_verified` property to user models

* Added `requires_verification` argument to `get_users_router`and `get_auth_router`

* Additional dependencies added for verification in `fastapi_users/authentication/__init__.py`

* Update tests for new behaviour

* Update `README.md` to describe a workaround for possible problems during testing, by exceeding ulimit file descriptor limit

Co-authored-by: Mark Todd <markpeter.todd@hotmail.co.uk>

* Restored docs to original state.

* All other modifications reqested added

Kebab-case on request-verify-token
SECRET now used as test string
Other minor changes

Co-authored-by: Mark Todd <markpeter.todd@hotmail.co.uk>

* Embed token in body in verify route

* Reorganize checks in verify route and add unit test

* Ignore coverage on Protocol classes

* Tweak verify_user function to take full user in parameter

* Improve unit tests structure regarding parametrized test client

* Make after_verification_request optional to be more consistent with other routers

* Tweak status codes on verify routes

* Write documentation for verification feature

* Add not released warning on verify docs

Co-authored-by: Edd Salkield <edd@salkield.uk>
Co-authored-by: Mark Todd <markpeter.todd@hotmail.co.uk>
2021-01-12 10:44:42 +01:00

2.4 KiB
Raw Blame History

User model

FastAPI Users defines a minimal User model for authentication purposes. It is structured like this:

  • id (UUID4) Unique identifier of the user. Default to a UUID4.
  • email (str) Email of the user. Validated by email-validator.
  • is_active (bool) Whether or not the user is active. If not, login and forgot password requests will be denied. Default to True.
  • is_verified (bool) Whether or not the user is verified. Optional but helpful with the verify router logic. Default to False.
  • is_superuser (bool) Whether or not the user is a superuser. Useful to implement administration logic. Default to False.

Define your models

There are four Pydantic models variations provided as mixins:

  • BaseUser, which provides the basic fields and validation ;
  • BaseCreateUser, dedicated to user registration, which consists of compulsory email and password fields ;
  • BaseUpdateUser, dedicated to user profile update, which adds an optional password field ;
  • BaseUserDB, which is a representation of the user in database, adding a hashed_password field.

You should define each of those variations, inheriting from each mixin:

from fastapi_users import models


class User(models.BaseUser):
    pass


class UserCreate(models.BaseUserCreate):
    pass


class UserUpdate(User, models.BaseUserUpdate):
    pass


class UserDB(User, models.BaseUserDB):
    pass

You can of course add your own properties there to fit to your needs!

Password validation

FastAPI Users doesn't provide a default password validation, but you can implement it easily with a Pydantic validator on the UserCreate class. Here is a simple example to check if the password is at least six characters long:

from fastapi_users import models
from pydantic import validator


class UserCreate(models.BaseUserCreate):
    @validator('password')
    def valid_password(cls, v: str):
        if len(v) < 6:
            raise ValueError('Password should be at least 6 characters')
        return v

Next steps

Depending on your database backend, the database configuration will differ a bit.

I'm using SQLAlchemy

I'm using MongoDB

I'm using Tortoise ORM