如果用户未使用 FastAPI-Login 包登录,则重定向到登录页面

Ech*_*yak 4 python fastapi

我想在用户未登录时将他们重定向到登录页面。

这是我的代码:

from fastapi import (
    Depends,
    FastAPI,
    HTTPException,
    status,
    Body,
    Request
)
from fastapi.encoders import jsonable_encoder
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from fastapi.responses import HTMLResponse, RedirectResponse
import app.models as models
import app.database as database
from datetime import datetime, timedelta
from jose import JWTError, jwt
from starlette.responses import FileResponse
from fastapi_login import LoginManager
from fastapi_login.exceptions import InvalidCredentialsException
from fastapi import Cookie
import re

app = FastAPI()

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
manager = LoginManager(SECRET_KEY, token_url="/auth/login", use_cookie=True)
manager.cookie_name = "token"


@app.get("/")
@app.get("/item")
async def read_index(user=Depends(manager)):
    try:
        return FileResponse('item.html')
    except status.HTTP_401_UNAUTHORIZED:
        return RedirectResponse(url="/login", status_code=status.HTTP_302_FOUND)
Run Code Online (Sandbox Code Playgroud)

但是,当我访问此页面时:localhost:8000/item,我得到以下信息:

{"detail":"Not authenticated"}
Run Code Online (Sandbox Code Playgroud)

Chr*_*ris 7

从您提供的代码片段来看,您似乎正在使用(第三方)FastAPI-Login包。他们的文档Exception建议在实例上使用自定义,如果用户未登录,LoginManager可以使用该自定义将用户重定向到该页面。login

工作示例:

下面的身份验证基于cookieAuthorization ,但您也可以在标头中传递令牌。/protected未登录时导航至路线以使重定向生效。

from fastapi import FastAPI, Depends, Request, Response, status
from starlette.responses import RedirectResponse, HTMLResponse, JSONResponse
from fastapi.security import OAuth2PasswordRequestForm
from fastapi_login.exceptions import InvalidCredentialsException
from fastapi_login import LoginManager

class NotAuthenticatedException(Exception):
    pass
    
app = FastAPI()
SECRET = "super-secret-key"
manager = LoginManager(SECRET, '/login', use_cookie=True, custom_exception=NotAuthenticatedException)


DB = {
    'users': {
        'johndoe@mail.com': {
            'name': 'John Doe',
            'password': 'hunter2'
        }
    }
}

def query_user(user_id: str):
    return DB['users'].get(user_id)


@manager.user_loader()
def load_user(user_id: str):
    user = DB['users'].get(user_id)
    return user
    
 
@app.exception_handler(NotAuthenticatedException)
def auth_exception_handler(request: Request, exc: NotAuthenticatedException):
    """
    Redirect the user to the login page if not logged in
    """
    return RedirectResponse(url='/login')
    

@app.get("/login", response_class=HTMLResponse)
def login_form():
    return """
    <!DOCTYPE html>
    <html>
       <body>
          <form method="POST"  action="/login">
             <label for="username">Username:</label><br>
             <input type="text" id="username" name="username" value="johndoe@mail.com"><br>
             <label for="password">Password:</label><br>
             <input type="password" id="password" name="password" value="hunter2"><br><br>
             <input type="submit" value="Submit">
          </form>
       </body>
    </html>
    """

    
@app.post('/login')
def login(data: OAuth2PasswordRequestForm = Depends()):
    email = data.username
    password = data.password
    user = query_user(email)
    if not user:
        # you can return any response or error of your choice
        raise InvalidCredentialsException
    elif password != user['password']:
        raise InvalidCredentialsException

    token = manager.create_access_token(data={'sub': email})
    response = RedirectResponse(url="/protected",status_code=status.HTTP_302_FOUND)
    manager.set_cookie(response, token)
    return response


@app.get('/protected')
def protected_route(user=Depends(manager)):
    return {'user': user}
Run Code Online (Sandbox Code Playgroud)