You need to enable JavaScript to run this app. 如何在不使用Express的前提下为Apollo Server实现社交登录
优惠活动
大模型
产品
解决方案
定价
更多

如何在不使用Express的前提下为Apollo Server实现社交登录

完全可以不引入Express,基于你当前的apollo-server + type-graphql技术栈实现Google社交登录,具体实现方案如下:


1. 新增依赖安装

首先安装所需的额外依赖:

npm install passport passport-google-oauth20 jsonwebtoken
npm install -D @types/passport @types/passport-google-oauth20 @types/jsonwebtoken

2. 封装Google OAuth验证工具

不需要将Passport挂载为Express中间件,直接封装成独立的验证函数即可,示例代码:

// src/utils/googleAuth.ts
import passport from 'passport'
import { Strategy as GoogleStrategy } from 'passport-google-oauth20'
import { prisma } from './prisma' // 你的prisma实例

// 初始化Google策略
passport.use(new GoogleStrategy({
  clientID: process.env.GOOGLE_CLIENT_ID!,
  clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
  callbackURL: process.env.GOOGLE_CALLBACK_URL!,
  passReqToCallback: true
}, async (req, accessToken, refreshToken, profile, done) => {
  try {
    // 查找或创建对应用户
    let user = await prisma.user.findUnique({
      where: { googleId: profile.id }
    })
    if (!user) {
      user = await prisma.user.create({
        data: {
          googleId: profile.id,
          email: profile.emails?.[0]?.value,
          name: profile.displayName,
          avatar: profile.photos?.[0]?.value
        }
      })
    }
    return done(null, user)
  } catch (err) {
    return done(err, null)
  }
}))

// 封装授权码验证函数
export const verifyGoogleCode = (code: string) => {
  return new Promise((resolve, reject) => {
    passport.authenticate('google', { scope: ['email', 'profile'] }, (err, user) => {
      if (err) reject(err)
      resolve(user)
    })({ query: { code } } as any, {} as any, () => {})
  })
}

3. 定义TypeGraphQL的认证类型与Resolver

// src/resolvers/AuthResolver.ts
import { Resolver, Mutation, Arg, ObjectType, Field } from 'type-graphql'
import jwt from 'jsonwebtoken'
import { verifyGoogleCode } from '../utils/googleAuth'
import { User } from '../entities/User' // 你的User实体

@ObjectType()
class AuthPayload {
  @Field()
  token: string

  @Field(() => User)
  user: User
}

@Resolver()
export class AuthResolver {
  @Mutation(() => AuthPayload)
  async googleAuth(@Arg('code') code: string) {
    const user = await verifyGoogleCode(code) as User
    // 生成JWT
    const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET!, { expiresIn: '7d' })
    return { token, user }
  }
}

4. 改造现有index.ts,加入Context解析逻辑

修改你的启动文件,从请求头中解析JWT并注入到上下文:

import 'reflect-metadata'
import * as tq from 'type-graphql'
import { ApolloServer } from 'apollo-server'
import jwt from 'jsonwebtoken'
import { ProfileResolver, UserResolver } from './resolvers'
import { AuthResolver } from './resolvers/AuthResolver'
import { prisma } from './utils/prisma'

const PORT = process.env.PORT || 5000

const app = async () => {
    const schema = await tq.buildSchema({resolvers: [UserResolver, ProfileResolver, AuthResolver]})

    const server = new ApolloServer({ 
        schema,
        context: async ({ req }) => {
          const token = req.headers.authorization?.replace('Bearer ', '')
          let userId = null
          if (token) {
            try {
              const payload = jwt.verify(token, process.env.JWT_SECRET!) as { userId: string }
              userId = payload.userId
            } catch {}
          }
          return { prisma, userId }
        }
    })

    const { url } = await server.listen(PORT)
    console.log(`Server is running at ${url}`)
}

app()

调用流程说明

前端先跳转Google OAuth授权页面,用户授权后Google会回调你配置的前端地址并带回code参数,前端将该code作为参数调用googleAuthMutation即可获取JWT,后续请求携带该JWT即可完成身份校验。


内容的提问来源于stack exchange,提问作者altF4

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.18 10:54:06