使用FastAPI在基于Python的GraphQL Server中进行身份验证

时间:2020-08-03 14:14:53

标签: python authentication graphql fastapi starlette

在使用FastAPI构建的GraphQL服务器中实现身份验证验证时遇到问题。以前,我们使用REST,但现在切换到GraphQL,我想知道如何实现此功能。以前,我们有不同的路由器,并且使用FastAPI可以像here那样使用依赖关系轻松地基于路由检查身份验证。我们正在授权标题中发送令牌,该令牌在后端进行解码,并取回user_id,然后我们可以在不同的端点中使用它。

我想知道在这里使用GraphQL如何工作。我们使用Graphene,并且我研究了Starlettes Authentication Examples,并介绍了如何设置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 个答案:

答案 0 :(得分:2)

在FastAPI文档或starlette文档中,他们使用add_route,这是在Starlette中添加路由而不声明特定操作的方法(与.get()、. post()等相同)。但这有一些缺点,我们无法像在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)])