将Spring Boot与GraphQLContext进行整合

我认为在Spring Boot上构建GraphQL时,有时我们希望对某些查询进行身份验证。在这种情况下,GraphQLContext非常有用。但是,关于GraphQLContext的信息非常有限,包括英文和日文。

GraphQLContext 是什么意思?

这个接口可以直接从GraphQL请求中创建具有相同名称的上下文。使用它可以通过上下文获取认证信息和角色权限。

依赖库

首先,在GraphQL的依赖库中,有很多关于应该指定什么的信息是杂乱无章的,但是看起来只要安装graphql-spring-boot-starter就可以了。

参考的网址是:https://github.com/graphql-java-kickstart/graphql-spring-boot

dependencies {
    implementation("com.graphql-java-kickstart:graphql-spring-boot-starter:8.0.0")
    runtimeOnly("com.graphql-java-kickstart:playground-spring-boot-starter:8.0.0")
    testImplementation("com.graphql-java-kickstart:graphql-spring-boot-starter-test:8.0.0")
}

整理目标

我认为,基本上,需要在使用移动应用程序或使用SPA构建的应用程序中进行GraphQL和身份验证的组合的请求。
在这次的情况下,我想要在HTTP标头中设置身份验证令牌,并发出请求。

通过GraphQL获取HttpServletRequest

要获取HttpServletRequest对象,可以使用以下代码。

import graphql.kickstart.tools.GraphQLMutationResolver
import graphql.schema.DataFetchingEnvironment

@Component
final class GraphQLMutationResolver: GraphQLMutationResolver {
    fun registerUser(input: User, environment: DataFetchingEnvironment): User {
       val context = environment.getContext<DefaultGraphQLServletContext>()
       val request: HttpServletRequest = context.getHttpServletRequest()
    }
}

环境:DataFetchingEnvironment在Query or Mutation指定的方法参数的末尾会自动添加。
此外,DefaultGraphQLServletContext是包含在graphql-java-servlet库中的一个类,它提供了graphql-java和servlet之间的桥梁。
DefaultGraphQLServletContext是一个实现了GraphQLContext的类,可以通过environment.getContext进行使用。

创建自己的GraphQLContext

每次都从DefaultGraphQLServletContext中提取头信息并进行认证是很麻烦的。因此,我想创建一个自定义的GraphQLContext。

首先,我们将创建一个AuthGraphQLBuilder来生成GraphQLContext。
在内部,我们将使用DefaultGraphQLServletContext来从Header中提取令牌。接下来,我们将使用提取到的令牌创建自定义的AuthContext。


import graphql.kickstart.execution.context.GraphQLContext
import graphql.kickstart.servlet.context.DefaultGraphQLServletContext
import graphql.kickstart.servlet.context.GraphQLServletContext
import graphql.kickstart.servlet.context.GraphQLServletContextBuilder

@Component
final class AuthGraphQLBuilder: GraphQLServletContextBuilder {
    val AUTHORIZATION = "Authorization"

    override fun build(httpServletRequest: HttpServletRequest?, httpServletResponse: HttpServletResponse?): GraphQLContext {
        val context = DefaultGraphQLServletContext.createServletContext().with(httpServletRequest).with(httpServletResponse).build()
        val accessToken: String? = context.httpServletRequest.getHeader(AUTHORIZATION)
        return AuthContext(formatAccessToken(accessToken), context)
    }

    override fun build(session: Session?, handshakeRequest: HandshakeRequest?): GraphQLContext {
        throw IllegalStateException("not support")
    }

    override fun build(): GraphQLContext {
        throw IllegalStateException("not support")
    }

    private fun formatAccessToken(rawToken: String?): String? {
        return rawToken?.replace("Bearer ", "")
    }
}

处理的内容很简单,只是在verifyToken中执行认证处理而已。


class AuthContext(accessToken: String?, private val context: GraphQLServletContext): GraphQLServletContext {

    init {
        accessToken?.also { token ->
            verifyToken(token)
        }
    }

    private fun verifyToken(accessToken: String) {
        // 認証処理をする
    }

    override fun getSubject(): Optional<Subject> {
        return context.subject
    }

    override fun getDataLoaderRegistry(): Optional<DataLoaderRegistry> {
        return context.dataLoaderRegistry
    }

    override fun getFileParts(): MutableList<Part> {
        return context.fileParts
    }

    override fun getParts(): MutableMap<String, MutableList<Part>> {
        return context.parts
    }

    override fun getHttpServletRequest(): HttpServletRequest {
        return context.httpServletRequest
    }

    override fun getHttpServletResponse(): HttpServletResponse {
        return context.httpServletResponse
    }
}

最后,使用方法很简单。只需指定AuthContext,并能获取到已经认证的上下文。

val authContext = environment.getContext<AuthContext>()

我最近对GraphQLContext进行了一些调查,但是发现信息很陈旧,无法找到可参考的内容,非常困扰。而且,由于找不到官方文档,更加困难。

对我有帮助的是下面这个Youtube视频:https://www.youtube.com/watch?v=YsM2VSnWUcg&t=421s。

广告
将在 10 秒后关闭
bannerAds