Проверка аутентификации на сервере GraphQL на базе Python с использованием FastAPI - PullRequest
2 голосов
/ 03 августа 2020

У меня возникли проблемы с реализацией проверки аутентификации на сервере GraphQL, построенном с помощью FastAPI. Раньше мы использовали REST, но теперь мы переходим на GraphQL, и мне интересно, как я могу это реализовать. Раньше у нас были разные маршрутизаторы, и с FastAPI легко проверить аутентификацию на основе маршрутов с использованием зависимостей, как в здесь . Мы отправляем токен в заголовке авторизации, который мы декодируем в бэкэнде, и получаем обратно user_id, который мы затем можем использовать в наших различных конечных точках.

Мне интересно, как это может работать с использованием GraphQL здесь. Мы используем Graphene , и я просмотрел Примеры аутентификации Starlettes , а также вводную часть настройки GraphQl

import binascii
from fastapi import FastAPI
from starlette.authentication import (
    AuthenticationBackend, AuthenticationError, SimpleUser, AuthCredentials
)
from starlette.graphql import GraphQLApp
from starlette.middleware import Middleware
from starlette.middleware.authentication import AuthenticationMiddleware

from schemas.root import my_schema


class BasicAuthBackend(AuthenticationBackend):
    async def authenticate(self, request):
        if "Authorization" not in request.headers:
            raise AuthenticationError('No auth credentials')

        auth = request.headers["Authorization"]
        try:
            id_token = auth.split('Bearer ')[1]
            decoded_token = auth.verify_id_token(id_token)

        except (ValueError, UnicodeDecodeError, binascii.Error) as exc:
            raise AuthenticationError('Invalid basic auth credentials')

        user_id = decoded_token['uid']
        return AuthCredentials(["authenticated"]), user_id


middleware = [
    Middleware(AuthenticationMiddleware, backend=BasicAuthBackend())
]

my_schema = Schema(
    query=RootQuery,
    mutation=RootMutation,
)

api = FastAPI(title=f"MyGraphQLServer", middleware=middleware)
api.add_route("/graphql", GraphQLApp(schema=my_schema))

для Например, представьте, что теперь я хочу аутентифицировать только запросы на мутацию, но не запросы запросов. Кроме того, я хочу получить доступ к user_id в каждом из моих преобразователей. Как лучше всего это сделать?

1 Ответ

2 голосов
/ 05 августа 2020

В документации FastAPI или документации Starlette они используют add_route, это способ добавить маршрут в Starlette без объявления определенной операции c (как это было бы с .get (), .post (), et c). Но у него есть некоторые недостатки, мы не можем добавлять зависимости, как в FastAPI, пример ниже

app.add_route(
"/graphql",
GraphQLApp(schema=graphene.Schema(query=Query), 
executor_class=AsyncioExecutor),
    dependencies=(Depends(SomeAuthorizationStuffHere)),
)

Итак, нам нужно сделать в FastAPI, я создал простое приложение с HTTPBasicAuth, вы можете расширить это с помощью другой метод, вам просто нужно включить router(s)

from fastapi import Query, Depends, Request, FastAPI, APIRouter
from fastapi.security import HTTPBasic, HTTPBasicCredentials
import graphene
from graphene import Field, Schema, String, ObjectType
from starlette.graphql import GraphQLApp


router = APIRouter()
app = FastAPI()
security = HTTPBasic()


class Query(ObjectType):
    hello = Field(String, name=String())

    def resolve_hello(root, info, name):
        coverage = info.context["request"].state.some_dep
        return f"Hello {some_dep.some_method(name)}"


graphql_app = GraphQLApp(schema=Schema(query=Query))


@router.post("/gql")
async def graphql(request: Request):
    return await graphql_app.handle_graphql(request=request)


app.include_router(router, dependencies=[Depends(security)])
...