diff --git a/Pipfile b/Pipfile index 57d146c7..4ad57667 100644 --- a/Pipfile +++ b/Pipfile @@ -41,6 +41,7 @@ motor = ">=2.2.0,<3.0.0" tortoise-orm = ">=0.15.18,<0.17.0" makefun = ">=1.9.2,<1.10" typing-extensions = ">=3.7.4.3" +Deprecated=">=1.2.10,<2.0.0" [requires] python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock index 2f02302b..6045de60 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "88a6a8c866df1d4b28880dbb26395bf1463e4f0d79730c18dedd4834f206aaa4" + "sha256": "3a4fd82af093b614076b951c791b974533d49a6789e48228082552d34186950f" }, "pipfile-spec": 6, "requires": { @@ -119,6 +119,14 @@ "index": "pypi", "version": "==0.4.1" }, + "deprecated": { + "hashes": [ + "sha256:525ba66fb5f90b07169fdd48b6373c18f1ee12728ca277ca44567a367d9d7f74", + "sha256:a766c1dccb30c5f6eb2b203f87edd1d8588847709c78589e1521d769addc8218" + ], + "index": "pypi", + "version": "==1.2.10" + }, "dnspython": { "hashes": [ "sha256:95d12f6ef0317118d2a1a6fc49aac65ffec7eb8087474158f42f26a639135216", @@ -396,6 +404,12 @@ ], "index": "pypi", "version": "==3.7.4.3" + }, + "wrapt": { + "hashes": [ + "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7" + ], + "version": "==1.12.1" } }, "develop": { diff --git a/fastapi_users/authentication/__init__.py b/fastapi_users/authentication/__init__.py index eba64491..43241ff5 100644 --- a/fastapi_users/authentication/__init__.py +++ b/fastapi_users/authentication/__init__.py @@ -1,7 +1,8 @@ import re -from inspect import Parameter, Signature +from inspect import Parameter, Signature, signature from typing import Optional, Sequence +from deprecated import deprecated from fastapi import Depends, HTTPException, status from makefun import with_signature @@ -47,38 +48,65 @@ class Authenticator: self.backends = backends self.user_db = user_db - self.get_current_user = self.get_auth_dependency(required=True) - self.get_current_active_user = self.get_auth_dependency( - required=True, active=True + self.get_current_user = self._deprecated_current_user("get_current_user") + self.get_current_active_user = self._deprecated_current_user( + "get_current_active_user", active=True ) - self.get_current_verified_user = self.get_auth_dependency( - required=True, active=True, verified=True + self.get_current_verified_user = self._deprecated_current_user( + "get_current_verified_user", active=True, verified=True ) - self.get_current_superuser = self.get_auth_dependency( - required=True, active=True, superuser=True + self.get_current_superuser = self._deprecated_current_user( + "get_current_superuser", active=True, superuser=True ) - self.get_current_verified_superuser = self.get_auth_dependency( - required=True, active=True, verified=True, superuser=True + self.get_current_verified_superuser = self._deprecated_current_user( + "get_current_verified_superuser", + active=True, + verified=True, + superuser=True, ) - self.get_optional_current_user = self.get_auth_dependency() - self.get_optional_current_active_user = self.get_auth_dependency(active=True) - self.get_optional_current_verified_user = self.get_auth_dependency( - active=True, verified=True + self.get_optional_current_user = self._deprecated_current_user( + "get_optional_current_user", optional=True ) - self.get_optional_current_superuser = self.get_auth_dependency( - active=True, superuser=True + self.get_optional_current_active_user = self._deprecated_current_user( + "get_optional_current_active_user", optional=True, active=True ) - self.get_optional_current_verified_superuser = self.get_auth_dependency( - active=True, verified=True, superuser=True + self.get_optional_current_verified_user = self._deprecated_current_user( + "get_optional_current_verified_user", + optional=True, + active=True, + verified=True, + ) + self.get_optional_current_superuser = self._deprecated_current_user( + "get_optional_current_superuser", optional=True, active=True, superuser=True + ) + self.get_optional_current_verified_superuser = self._deprecated_current_user( + "get_optional_current_verified_superuser", + optional=True, + active=True, + verified=True, + superuser=True, ) - def get_auth_dependency( + def current_user( self, - required: bool = False, + optional: bool = False, active: bool = False, verified: bool = False, superuser: bool = False, ): + """ + Return a dependency callable to retrieve currently authenticated user. + + :param optional: If `true`, `None` is returned if there is no + authenticated user or if it doesn't pass the other requirements. + Otherwise, an exception is raised. Defaults to `false`. + :param active: If `true`, raise an exception if + the authenticated user is inactive. Defaults to `false`. + :param verified: If `true`, raise an exception if + the authenticated user is not verified. Defaults to `false`. + :param superuser: If `true`, raise an exception if + the authenticated user is not a superuser. Defaults to `false`. + """ # Here comes some blood magic 🧙‍♂️ # Thank to "makefun", we are able to generate callable # with a dynamic number of dependencies at runtime. @@ -97,22 +125,47 @@ class Authenticator: raise DuplicateBackendNamesError() @with_signature(signature) - async def auth_dependency(*args, **kwargs): + async def current_user_dependency(*args, **kwargs): return await self._authenticate( *args, - required=required, + optional=optional, active=active, verified=verified, superuser=superuser, **kwargs ) - return auth_dependency + return current_user_dependency + + def _deprecated_current_user( + self, + func_name: str, + optional: bool = False, + active: bool = False, + verified: bool = False, + superuser: bool = False, + ): + current_user_dependency = self.current_user( + optional, active, verified, superuser + ) + + @deprecated( + version="5.1.0", + reason=( + "You should call `current_user` with your own set of parameters. " + "See: https://frankie567.github.io/fastapi-users/" + ), + ) + @with_signature(signature(current_user_dependency), func_name=func_name) + async def deprecated_current_user_dependency(*args, **kwargs): + return await current_user_dependency(*args, **kwargs) + + return deprecated_current_user_dependency async def _authenticate( self, *args, - required: bool = False, + optional: bool = False, active: bool = False, verified: bool = False, superuser: bool = False, @@ -136,6 +189,6 @@ class Authenticator: status_code = status.HTTP_403_FORBIDDEN user = None - if not user and required: + if not user and not optional: raise HTTPException(status_code=status_code) return user diff --git a/fastapi_users/fastapi_users.py b/fastapi_users/fastapi_users.py index 69044081..746d8b9b 100644 --- a/fastapi_users/fastapi_users.py +++ b/fastapi_users/fastapi_users.py @@ -41,11 +41,14 @@ class FastAPIUsers: :param user_db_model: Pydantic model of a DB representation of a user. :attribute create_user: Helper function to create a user programmatically. + :attribute current_user: Dependency callable getter to inject authenticated user + with a specific set of parameters. :attribute get_current_user: Dependency callable to inject authenticated user. :attribute get_current_active_user: Dependency callable to inject active user. :attribute get_current_verified_user: Dependency callable to inject verified user. :attribute get_current_superuser: Dependency callable to inject superuser. - :attribute get_current_verified_superuser: Dependency callable to inject verified superuser. + :attribute get_current_verified_superuser: Dependency callable to inject + verified superuser. """ db: BaseUserDatabase @@ -80,6 +83,7 @@ class FastAPIUsers: self.verify_user = get_verify_user(db) self.get_user = get_get_user(db) + self.current_user = self.authenticator.current_user self.get_current_user = self.authenticator.get_current_user self.get_current_active_user = self.authenticator.get_current_active_user self.get_current_verified_user = self.authenticator.get_current_verified_user