如何在不使用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
相关产品推荐
相关产品推荐

