在使用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。最好的方法是什么?
答案 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)])