chore: switch to Fastify & Mercurius with auth for subscription, queries and mutations

This commit is contained in:
M1000fr 2024-11-25 23:27:37 +01:00
parent eb3f3a8de9
commit 7dd819de7e
8 changed files with 50 additions and 65 deletions

View File

@ -1,9 +0,0 @@
import { Controller, Get } from '@nestjs/common';
@Controller()
export class AppController {
@Get()
getHello(): string {
return 'Hello World!';
}
}

View File

@ -5,9 +5,7 @@ import { GraphQLModule } from "@nestjs/graphql";
import { MercuriusDriver, MercuriusDriverConfig } from "@nestjs/mercurius";
import { AppService } from "./app.service";
import { AuthModule } from "./auth/auth.module";
import { UserModule } from "./user/user.module";
import { AppController } from "./app.controller";
import { GraphqlOptions } from "./graphqlOptions";
@ -24,10 +22,8 @@ import { GraphqlOptions } from "./graphqlOptions";
driver: MercuriusDriver,
useClass: GraphqlOptions,
}),
AuthModule,
UserModule,
],
providers: [AppService],
controllers: [AppController],
})
export class AppModule {}

View File

@ -1,36 +0,0 @@
import {
CanActivate,
ExecutionContext,
Injectable,
UnauthorizedException,
} from "@nestjs/common";
import { JwtService } from "@nestjs/jwt";
import { Request } from "express";
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private jwtService: JwtService) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const token = this.extractTokenFromHeader(request);
if (!token) {
throw new UnauthorizedException();
}
try {
const payload = await this.jwtService.verifyAsync(token, {
secret: process.env.JWT_SECRET,
});
request["user"] = payload;
} catch {
throw new UnauthorizedException();
}
return true;
}
private extractTokenFromHeader(request: Request): string | undefined {
const [type, token] = request.headers.authorization?.split(" ") ?? [];
return type === "Bearer" ? token : undefined;
}
}

View File

@ -1,4 +0,0 @@
import { Module } from '@nestjs/common';
@Module({})
export class AuthModule {}

View File

@ -1,14 +1,46 @@
import { Injectable, UnauthorizedException } from "@nestjs/common";
import { GqlOptionsFactory } from "@nestjs/graphql";
import { Injectable } from "@nestjs/common";
import { JwtService } from "@nestjs/jwt";
import { MercuriusDriverConfig } from "@nestjs/mercurius";
@Injectable()
export class GraphqlOptions implements GqlOptionsFactory {
constructor(private readonly jwtService: JwtService) {}
createGqlOptions(): Promise<MercuriusDriverConfig> | MercuriusDriverConfig {
return {
autoSchemaFile: "src/schema.gql",
subscription: true,
graphiql: true,
subscription: {
context: (_connection, request) => {
const authorization = request.headers.authorization;
if (!authorization) throw new UnauthorizedException();
const token = authorization.split(" ")[1];
if (!token) throw new UnauthorizedException();
try {
const user = this.jwtService.verify(token);
return { user };
} catch (error) {
throw new UnauthorizedException();
}
},
},
graphiql: false,
context: (req) => {
const authorization = req.headers.authorization;
if (!authorization) throw new UnauthorizedException();
const token = authorization.split(" ")[1];
if (!token) throw new UnauthorizedException();
try {
const user = this.jwtService.verify(token);
return { user };
} catch (error) {
throw new UnauthorizedException();
}
},
};
}
}

View File

@ -24,7 +24,7 @@ input CreateUserInput {
}
input UpdateUserInput {
username: String!
username: String
isAdmin: Boolean
id: String!
}

View File

@ -6,6 +6,6 @@ export class UpdateUserInput extends PartialType(CreateUserInput) {
@Field()
id: string;
@Field()
@Field({ nullable: true })
username: string;
}

View File

@ -1,12 +1,18 @@
import { Args, Mutation, Query, Resolver, Subscription } from "@nestjs/graphql";
import {
Args,
Mutation,
Query,
Resolver,
Subscription
} from "@nestjs/graphql";
import { UserService } from "./user.service";
import { User } from "./user.entity";
import { CreateUserInput } from "./dto/create-user.input";
import { UpdateUserInput } from "./dto/update-user.input";
import { SetUserPasswordInput } from "./dto/setpassword-user.input";
import { UpdateUserInput } from "./dto/update-user.input";
import { User } from "./user.entity";
import { UserService } from "./user.service";
import { PubSub } from 'graphql-subscriptions';
import { PubSub } from "graphql-subscriptions";
const pubSub = new PubSub();