mirror of
				https://github.com/fastapi-users/fastapi-users.git
				synced 2025-11-04 14:45:50 +08:00 
			
		
		
		
	* Added login endpoint docs
* make format
* Changed login route into multiple examples.
* Added reset password router docs
* Updated /{id} routes for user
* Updated /me routes
* Fixed user already exists response description
* Updated the /register route
* Updated verify routes
* Updated oauth2 endpoints.
* Applied `make format`
* Renamed Authentication methods for getting their openapi schemas
- `get_login_responses_success` -> `get_openapi_login_responses_success`
- `get_logout_responses_success` -> `get_openapi_logout_responses_success`
* Fixed flake8 errors
* Not using `Final` to keep python37 compatibility
Co-authored-by: François Voron <fvoron@gmail.com>
		
	
		
			
				
	
	
		
			167 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			167 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
from typing import (
 | 
						|
    Any,
 | 
						|
    AsyncGenerator,
 | 
						|
    Callable,
 | 
						|
    Dict,
 | 
						|
    Generic,
 | 
						|
    List,
 | 
						|
    Optional,
 | 
						|
    Sequence,
 | 
						|
)
 | 
						|
 | 
						|
import httpx
 | 
						|
import pytest
 | 
						|
from fastapi import Depends, FastAPI, Request, status
 | 
						|
from fastapi.security.base import SecurityBase
 | 
						|
 | 
						|
from fastapi_users import models
 | 
						|
from fastapi_users.authentication import (
 | 
						|
    Authenticator,
 | 
						|
    BaseAuthentication,
 | 
						|
    DuplicateBackendNamesError,
 | 
						|
)
 | 
						|
from fastapi_users.manager import BaseUserManager
 | 
						|
from tests.conftest import UserDB
 | 
						|
 | 
						|
 | 
						|
class MockSecurityScheme(SecurityBase):
 | 
						|
    def __call__(self, request: Request) -> Optional[str]:
 | 
						|
        return "mock"
 | 
						|
 | 
						|
 | 
						|
class BackendNone(
 | 
						|
    Generic[models.UC, models.UD], BaseAuthentication[str, models.UC, models.UD]
 | 
						|
):
 | 
						|
    def __init__(self, name="none"):
 | 
						|
        super().__init__(name, logout=False)
 | 
						|
        self.scheme = MockSecurityScheme()
 | 
						|
 | 
						|
    async def __call__(
 | 
						|
        self,
 | 
						|
        credentials: Optional[str],
 | 
						|
        user_manager: BaseUserManager[models.UC, models.UD],
 | 
						|
    ) -> Optional[models.UD]:
 | 
						|
        return None
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def get_openapi_login_responses_success() -> Dict[str, Any]:
 | 
						|
        return {}
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def get_openapi_logout_responses_success() -> Dict[str, Any]:
 | 
						|
        return {}
 | 
						|
 | 
						|
 | 
						|
class BackendUser(
 | 
						|
    Generic[models.UC, models.UD], BaseAuthentication[str, models.UC, models.UD]
 | 
						|
):
 | 
						|
    def __init__(self, user: models.UD, name="user"):
 | 
						|
        super().__init__(name, logout=False)
 | 
						|
        self.scheme = MockSecurityScheme()
 | 
						|
        self.user = user
 | 
						|
 | 
						|
    async def __call__(
 | 
						|
        self,
 | 
						|
        credentials: Optional[str],
 | 
						|
        user_manager: BaseUserManager[models.UC, models.UD],
 | 
						|
    ) -> Optional[models.UD]:
 | 
						|
        return self.user
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def get_openapi_login_responses_success() -> Dict[str, Any]:
 | 
						|
        return {}
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def get_openapi_logout_responses_success() -> Dict[str, Any]:
 | 
						|
        return {}
 | 
						|
 | 
						|
 | 
						|
@pytest.fixture
 | 
						|
@pytest.mark.asyncio
 | 
						|
def get_test_auth_client(get_user_manager, get_test_client):
 | 
						|
    async def _get_test_auth_client(
 | 
						|
        backends: List[BaseAuthentication],
 | 
						|
        get_enabled_backends: Optional[
 | 
						|
            Callable[..., Sequence[BaseAuthentication]]
 | 
						|
        ] = None,
 | 
						|
    ) -> AsyncGenerator[httpx.AsyncClient, None]:
 | 
						|
        app = FastAPI()
 | 
						|
        authenticator = Authenticator(backends, get_user_manager)
 | 
						|
 | 
						|
        @app.get("/test-current-user")
 | 
						|
        def test_current_user(
 | 
						|
            user: UserDB = Depends(
 | 
						|
                authenticator.current_user(get_enabled_backends=get_enabled_backends)
 | 
						|
            ),
 | 
						|
        ):
 | 
						|
            return user
 | 
						|
 | 
						|
        @app.get("/test-current-active-user")
 | 
						|
        def test_current_active_user(
 | 
						|
            user: UserDB = Depends(
 | 
						|
                authenticator.current_user(
 | 
						|
                    active=True, get_enabled_backends=get_enabled_backends
 | 
						|
                )
 | 
						|
            ),
 | 
						|
        ):
 | 
						|
            return user
 | 
						|
 | 
						|
        @app.get("/test-current-superuser")
 | 
						|
        def test_current_superuser(
 | 
						|
            user: UserDB = Depends(
 | 
						|
                authenticator.current_user(
 | 
						|
                    active=True,
 | 
						|
                    superuser=True,
 | 
						|
                    get_enabled_backends=get_enabled_backends,
 | 
						|
                )
 | 
						|
            ),
 | 
						|
        ):
 | 
						|
            return user
 | 
						|
 | 
						|
        async for client in get_test_client(app):
 | 
						|
            yield client
 | 
						|
 | 
						|
    return _get_test_auth_client
 | 
						|
 | 
						|
 | 
						|
@pytest.mark.authentication
 | 
						|
@pytest.mark.asyncio
 | 
						|
async def test_authenticator(get_test_auth_client, user):
 | 
						|
    async for client in get_test_auth_client([BackendNone(), BackendUser(user)]):
 | 
						|
        response = await client.get("/test-current-user")
 | 
						|
        assert response.status_code == status.HTTP_200_OK
 | 
						|
 | 
						|
 | 
						|
@pytest.mark.authentication
 | 
						|
@pytest.mark.asyncio
 | 
						|
async def test_authenticator_none(get_test_auth_client):
 | 
						|
    async for client in get_test_auth_client(
 | 
						|
        [BackendNone(), BackendNone(name="none-bis")]
 | 
						|
    ):
 | 
						|
        response = await client.get("/test-current-user")
 | 
						|
        assert response.status_code == status.HTTP_401_UNAUTHORIZED
 | 
						|
 | 
						|
 | 
						|
@pytest.mark.authentication
 | 
						|
@pytest.mark.asyncio
 | 
						|
async def test_authenticator_none_enabled(get_test_auth_client, user):
 | 
						|
    backend_none = BackendNone()
 | 
						|
    backend_user = BackendUser(user)
 | 
						|
 | 
						|
    async def get_enabled_backends():
 | 
						|
        return [backend_none]
 | 
						|
 | 
						|
    async for client in get_test_auth_client(
 | 
						|
        [backend_none, backend_user], get_enabled_backends
 | 
						|
    ):
 | 
						|
        response = await client.get("/test-current-user")
 | 
						|
        assert response.status_code == status.HTTP_401_UNAUTHORIZED
 | 
						|
 | 
						|
 | 
						|
@pytest.mark.authentication
 | 
						|
@pytest.mark.asyncio
 | 
						|
async def test_authenticators_with_same_name(get_test_auth_client):
 | 
						|
    with pytest.raises(DuplicateBackendNamesError):
 | 
						|
        async for _ in get_test_auth_client([BackendNone(), BackendNone()]):
 | 
						|
            pass
 |