首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用passport +JWT或会话保护GraphQL应用程序接口?(举例说明)

使用passport +JWT或会话保护GraphQL应用程序接口?(举例说明)
EN

Stack Overflow用户
提问于 2020-12-24 17:29:20
回答 1查看 290关注 0票数 0

给出一点背景:我正在编写一个应用程序接口来服务于React中的内部内容管理系统,这需要谷歌登录和一个React Native应用程序,它应该支持短信、电子邮件和苹果登录,我被困在哪种身份验证方式上是最好的,我目前有一个示例身份验证流程,其中团队成员使用谷歌登录,刷新令牌在httpOnly cookie中发送并存储在客户端的变量中,然后该令牌可以交换为accessToken。cookie中的刷新令牌还有一个tokenVersion,它在发送accessToken之前进行检查,这确实会向数据库添加一些额外的负载,但如果有人的帐户被盗,则可以增加该值。在允许任何GraphQL查询/突变之前,将解码用户的令牌并将其添加到GraphQL上下文中,以便我可以使用graphql-shield检查角色,如果需要,还可以在查询/突变中访问用户以执行db操作

因为我仍然在访问数据库,即使它只在页面/应用程序加载时使用一次,我想知道这是不是一个好方法,或者使用会话会更好

代码语言:javascript
复制
// index.ts
import "./passport"

const main = () => {
  const server = fastify({ logger })
  const prisma = new PrismaClient()

  const apolloServer = new ApolloServer({
    schema: applyMiddleware(schema, permissions),
    context: (request: Omit<Context, "prisma">) => ({ ...request, prisma }),
    tracing: __DEV__,
  })

  server.register(fastifyCookie)
  server.register(apolloServer.createHandler())
  server.register(fastifyPassport.initialize())

  server.get(
    "/auth/google",
    {
      preValidation: fastifyPassport.authenticate("google", {
        scope: ["profile", "email"],
        session: false,
      }),
    },
    // eslint-disable-next-line @typescript-eslint/no-empty-function
    async () => {}
  )

  server.get(
    "/auth/google/callback",
    {
      preValidation: fastifyPassport.authorize("google", { session: false }),
    },
    async (request, reply) => {
      // Store user in database
      // const user = existingOrCreatedUser
      // sendRefreshToken(user, reply) < send httpOnly cookie to client
      // const accessToken = createAccessToken(user)
      // reply.send({ accessToken, user }) < send accessToken
    }
  )
      
  server.get("/refresh_token", async (request, reply) => {
    const token = request.cookies.fid

    if (!token) {
      return reply.send({ accessToken: "" })
    }

    let payload

    try {
      payload = verify(token, secret)
    } catch {
      return reply.send({ accessToken: "" })
    }

    const user = await prisma.user.findUnique({
      where: { id: payload.userId },
    })

    if (!user) {
      return reply.send({ accessToken: "" })
    }

    // Check live tokenVersion against user's one in case it was incremented
    if (user.tokenVersion !== payload.tokenVersion) {
      return reply.send({ accessToken: "" })
    }

    sendRefreshToken(user, reply)

    return reply.send({ accessToken: createAccessToken(user) })
  })

  server.listen(port)
}
代码语言:javascript
复制
// passport.ts
import fastifyPassport from "fastify-passport"
import { OAuth2Strategy } from "passport-google-oauth"

fastifyPassport.registerUserSerializer(async (user) => user)
fastifyPassport.registerUserDeserializer(async (user) => user)

fastifyPassport.use(
  new OAuth2Strategy(
    {
      clientID: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
      callbackURL: "http://localhost:4000/auth/google/callback",
    },
    (_accessToken, _refreshToken, profile, done) => done(undefined, profile)
  )
)
代码语言:javascript
复制
// permissions/index.ts
import { shield } from "graphql-shield"
import { rules } from "./rules"

export const permissions = shield({
  Mutation: {
    createOneShopLocation: rules.isAuthenticatedUser,
  },
})
代码语言:javascript
复制
// permissions/rules.ts
import { rule } from "graphql-shield"
import { Context } from "../context"

export const rules = {
  isAuthenticatedUser: rule()(async (_parent, _args, ctx: Context) => {
    const authorization = ctx.request.headers.authorization

    if (!authorization) {
      return false
    }

    try {
      const token = authorization.replace("Bearer", "")
      const payload = verify(token, secret)

      // mutative
      ctx.payload = payload

      return true
    } catch {
      return false
    }
  }),
}
EN

回答 1

Stack Overflow用户

发布于 2020-12-25 19:21:03

为了直接回答您的问题,您希望使用jwts进行访问,仅此而已。这些jwt应该与用户会话绑定在一起创建,但您不希望必须对它们进行管理。你想要一个用户身份聚合器来做这件事。

您最好删除处理用户登录/刷新的大部分代码,并使用用户身份聚合器。在处理用户身份验证流时,您会遇到一些常见的复杂性问题,这就是存在这些问题的原因。

最常见的是Auth0,但其价格和复杂性可能与您的预期不符。我建议浏览一下列表,选择最支持您的用例的一个:

或者您可以查看this article,它建议了一系列不同的替代方案以及它们所关注的内容

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65436426

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档