mirror of
				https://github.com/fastapi-users/fastapi-users.git
				synced 2025-10-31 17:38:30 +08:00 
			
		
		
		
	 7ad5f8073d
			
		
	
	7ad5f8073d
	
	
	
		
			
			* on_after_login minimal impl. Questions: is the spot logical for after method? Is after the internal login call. Would before_login be needed? Maybe not, as auth is the way to do pre-login things. Added fastapi request as a param just in case, as other callbacks had it too. Docs addition is missing. * tried to complete the implementation, but the test with user_manager.on_after_login.called fails though * move on_after_login tests to right place, to TestLogin. These ones pass. TODO: check TestCallback * on_after_login tests to TestCallback too, for oauth. Apparently test_redirect_url_router fires the callback too, I guess that's correct, am not using oauth myself. * fix formatting with make format * docs for on_after_login Co-authored-by: Toni Alatalo <toni.alatalo@gmail.com>
		
			
				
	
	
		
			95 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			95 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| from typing import Tuple
 | |
| 
 | |
| from fastapi import APIRouter, Depends, HTTPException, Request, Response, status
 | |
| from fastapi.security import OAuth2PasswordRequestForm
 | |
| 
 | |
| from fastapi_users import models
 | |
| from fastapi_users.authentication import AuthenticationBackend, Authenticator, Strategy
 | |
| from fastapi_users.manager import BaseUserManager, UserManagerDependency
 | |
| from fastapi_users.openapi import OpenAPIResponseType
 | |
| from fastapi_users.router.common import ErrorCode, ErrorModel
 | |
| 
 | |
| 
 | |
| def get_auth_router(
 | |
|     backend: AuthenticationBackend,
 | |
|     get_user_manager: UserManagerDependency[models.UP, models.ID],
 | |
|     authenticator: Authenticator,
 | |
|     requires_verification: bool = False,
 | |
| ) -> APIRouter:
 | |
|     """Generate a router with login/logout routes for an authentication backend."""
 | |
|     router = APIRouter()
 | |
|     get_current_user_token = authenticator.current_user_token(
 | |
|         active=True, verified=requires_verification
 | |
|     )
 | |
| 
 | |
|     login_responses: OpenAPIResponseType = {
 | |
|         status.HTTP_400_BAD_REQUEST: {
 | |
|             "model": ErrorModel,
 | |
|             "content": {
 | |
|                 "application/json": {
 | |
|                     "examples": {
 | |
|                         ErrorCode.LOGIN_BAD_CREDENTIALS: {
 | |
|                             "summary": "Bad credentials or the user is inactive.",
 | |
|                             "value": {"detail": ErrorCode.LOGIN_BAD_CREDENTIALS},
 | |
|                         },
 | |
|                         ErrorCode.LOGIN_USER_NOT_VERIFIED: {
 | |
|                             "summary": "The user is not verified.",
 | |
|                             "value": {"detail": ErrorCode.LOGIN_USER_NOT_VERIFIED},
 | |
|                         },
 | |
|                     }
 | |
|                 }
 | |
|             },
 | |
|         },
 | |
|         **backend.transport.get_openapi_login_responses_success(),
 | |
|     }
 | |
| 
 | |
|     @router.post(
 | |
|         "/login",
 | |
|         name=f"auth:{backend.name}.login",
 | |
|         responses=login_responses,
 | |
|     )
 | |
|     async def login(
 | |
|         request: Request,
 | |
|         response: Response,
 | |
|         credentials: OAuth2PasswordRequestForm = Depends(),
 | |
|         user_manager: BaseUserManager[models.UP, models.ID] = Depends(get_user_manager),
 | |
|         strategy: Strategy[models.UP, models.ID] = Depends(backend.get_strategy),
 | |
|     ):
 | |
|         user = await user_manager.authenticate(credentials)
 | |
| 
 | |
|         if user is None or not user.is_active:
 | |
|             raise HTTPException(
 | |
|                 status_code=status.HTTP_400_BAD_REQUEST,
 | |
|                 detail=ErrorCode.LOGIN_BAD_CREDENTIALS,
 | |
|             )
 | |
|         if requires_verification and not user.is_verified:
 | |
|             raise HTTPException(
 | |
|                 status_code=status.HTTP_400_BAD_REQUEST,
 | |
|                 detail=ErrorCode.LOGIN_USER_NOT_VERIFIED,
 | |
|             )
 | |
|         login_return = await backend.login(strategy, user, response)
 | |
|         await user_manager.on_after_login(user, request)
 | |
|         return login_return
 | |
| 
 | |
|     logout_responses: OpenAPIResponseType = {
 | |
|         **{
 | |
|             status.HTTP_401_UNAUTHORIZED: {
 | |
|                 "description": "Missing token or inactive user."
 | |
|             }
 | |
|         },
 | |
|         **backend.transport.get_openapi_logout_responses_success(),
 | |
|     }
 | |
| 
 | |
|     @router.post(
 | |
|         "/logout", name=f"auth:{backend.name}.logout", responses=logout_responses
 | |
|     )
 | |
|     async def logout(
 | |
|         response: Response,
 | |
|         user_token: Tuple[models.UP, str] = Depends(get_current_user_token),
 | |
|         strategy: Strategy[models.UP, models.ID] = Depends(backend.get_strategy),
 | |
|     ):
 | |
|         user, token = user_token
 | |
|         return await backend.logout(strategy, user, token, response)
 | |
| 
 | |
|     return router
 |