Не работает метод set_cookie класса RedirectResponse

Есть код аутентификации и авторизации пользователей на sqladmin:

class AdminBack(AuthenticationBackend):
    async def authenticate(self, request: Request) -> Response | bool:
        token = request.cookies.get('access_token')
        if not token:
            return False
        try:
            payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
            username: str = payload.get('sub')
            if username:
                return True
        except InvalidTokenError:
            return False
        return False
    
    async def login(self, request: Request) -> bool:
        form = await request.form()
        username = form.get('username')
        password = form.get('password')

        user = authenticate_user(username, password)
        if not user:
             raise HTTPException(status_code=401, detail="Invalid credentials")
        access_token = create_access_token(data={'sub': user['username']})
        response = RedirectResponse(url='/admin')
        response.set_cookie(key='access_token', value=access_token)
        return response
    
    async def logout(self, request: Request) -> bool:
        response = RedirectResponse(url='/admin')
        response.delete_cookie(key='access_token')
        return response

app = FastAPI()

engine = create_async_engine()

authentication_backend = AdminBack(secret_key=SECRET_KEY)


admin = Admin(app, engine, authentication_backend=authentication_backend)

После ввода в форму необходимых данных логина пароля: форма авторизации

метод login отрабатывает корректно (токен создается, объект response возвращается) до момента применения метода set_cookie(). Куки просто не устанавливаются (заголовка Set-cookie не появляется, как и самой куки с токеном), после чего естественно метод authenticate не может достать токен и я снова получаю пустую форму для ввода логина и пароля. При этом в отдельно вынесенном эндпоинте типа:

@app.get('/set/')
async def set_func(request: Request):
    token = create_access_token(data={'sub': fake_db['username']})
    response = RedirectResponse(url='/admin')
    response.set_cookie(key='access_token', value=token)
    return response

Все отрабатывает корректно.

В чем может быть причина?


Ответы (1 шт):

Автор решения: Олег Пронин

Разобрался. методы класса AuthenticationBackend в sqladmin не поддерживают установку кук через set_cookie, зато можно это сделать через работу с сессией:

 request.session.update({'access_token':access_token})

Вместо:

async def login(self, request: Request) -> bool:
        form = await request.form()
        username = form.get('username')
        password = form.get('password')

        user = authenticate_user(username, password)
        if not user:
             raise HTTPException(status_code=401, detail="Invalid credentials")
        access_token = create_access_token(data={'sub': user['username']})
        response = RedirectResponse(url='/admin')
        response.set_cookie(key='access_token', value=access_token)
        return response

Необходимо прописать:

async def login(self, request: Request) -> bool:
        form = await request.form()
        username = form.get('username')
        password = form.get('password')

        user = authenticate_user(username, password)
        if not user:
             raise HTTPException(status_code=401, detail="Invalid credentials")
        access_token = create_access_token(data={'sub': user['username']})
        request.session.update({'access_token': access_token})
        return True
→ Ссылка