๋ชจ๋์ @Module() ๋ฐ์ฝ๋ ์ดํฐ๋ก ์ฃผ์์ด ๋ฌ๋ฆฐ ํด๋์ค์
๋๋ค.
@Module() ๋ฐ์ฝ๋ ์ดํฐ๋ Nest๊ฐ ์ ํ๋ฆฌ์ผ์ด์
๊ตฌ์กฐ๋ฅผ ๊ตฌ์ฑํ๋ ๋ฐ ์ฌ์ฉํ๋ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ์ ๊ณตํฉ๋๋ค.
https://docs.nestjs.com/modules
์ด๋ ํ ์ค์ ๋ ์ ์ฉ๋์ด ์์ง ์์ ๋ชจ๋
์ค์ ์ด ์ ์ฉ๋์ด ์๊ฑฐ๋ ์ค์ ์ ์ ์ฉํ ์ ์๋ ๋ชจ๋
์ฆ์ ์ฌ์ฉํ ์ ์๋ ๋ชจ๋ ์ ๊ณต์ ์ธํธ(์: ๋์ฐ๋ฏธ, ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ๋ฑ)๋ฅผ ์ ๊ณตํ๋ ค๋ฉด @Global() ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ์ฌ ๋ชจ๋์ ์ ์ญ์ ์ผ๋ก ๋ง๋ค ์ ์๋ค.
๋๋ forRoot์์์ global: true๋ฅผ ํตํด์๋ ์ ์ญ ๋ชจ๋๋ก ๋ง๋ค ์ ์๋ค.
return {
global:true,
module: JwtModule,
providers: [JwtService],
exports: [JwtService],
};
์๋ ์ฝ๋๋ providers: [CatsService]์ ์ถ์ฝํ์
๋๋ค.
providers: [
{ provide: CatsService, useClass: CatsService },
];
provider์ ํ์
(์ฃผ์
๋์ผ ํ ์ธ์คํด์ค ํด๋์ค ์ด๋ฆ)
ํ๋ก๋ฐ์ด๋๋ก ์ฌ์ฉํ ํด๋์ค
์ฃผ์ ํ provider์ ์ธ์คํด์ค
Nestjs์์์ middleware๋ ๊ธฐ๋ณธ์ ์ผ๋ก express์ middleware์ ๋์ผํ๋ค.
NestMiddleware๋ฅผ implementsํ ํ use ํจ์๋ฅผ ์ฌ์ฉํด class๋ก ๊ตฌํํ๊ฑฐ๋ ํจ์๋ก ๊ตฌํํ ์ ์์ผ๋ฉฐ express์์์ ๊ฐ์ด, ๋์๋ ํญ์ next๋ฅผ ํธ์ถ ํด์ผํ๋ค.
import { NextFunction, Request, Response } from 'express';
export function jwtMiddleware(req: Request, res: Response, next: NextFunction) {
console.log(req.headers);
next();
}
forRoutes ๋ฉ์๋๋ฅผ ์ฌ์ฉํด ๋ผ์ฐํฐ์ RequestMethod๋ฅผ ํน์ ํ๋ค.
exclude ๋ฉ์๋๋ฅผ ์ฌ์ฉํด ํน์ ๋ผ์ฐํฐ์ RequestMethod๋ฅผ ์ ์ธ์ํฌ ์ ์๋ค.
export class AppModule implements NestModule{
configure(consumer: MiddlewareConsumer) {
consumer.apply(jwtMiddleware).forRoutes({
path: '/graphql',
method: RequestMethod.POST,
});
}
}
main.ts ํ์ผ์์ app.use(jwtMiddleware)๋ฅผ ์ ์ธํ๋ฉด ์ฑ ์ ์ฒด์ ์ ์ฉ์ํฌ ์ ์๋ค. ์ด ๊ฒ์ middleware๋ฅผ function์ผ๋ก ์ ์ธํ์ ๊ฒฝ์ฐ์๋ง ๊ฐ๋ฅํ๋ค. class๋ก ์ ์ธํ์ ๊ฒฝ์ฐ 1๋ฒ ๋ฐฉ๋ฒ๋ง ์ฌ์ฉ ๊ฐ๋ฅ
๊ฐ request์ ๋ํด request context๋ฅผ ์ฌ์ฉํ ์ ์๋ค. context๊ฐ ํจ์๋ก ์ ์๋๋ฉด ๊ฐ request๋ง๋ค ํธ์ถ๋๊ณ req ์์ฑ์ request ๊ฐ์ฒด๋ฅผ ๋ฐ๋๋ค.
context: ({ req }) => ({ user: req['user'] }),
//app.module์ graphQlModule์ ์ธ์๋ก ํ ๋น
@Query((returns) => User)
me(@Context() context) {
if (!context.user) {
return;
} else {
return context.user;
}
}
Authentication์ ์ํด ํ์ํ ํด๋์ค์ด๋ค.
(๋ก๊ทธ์ธํ์ง ์์ ์ฌ๋์ post๋ฅผ ๋ณด๋ผ ์ ์๋๋ก!!)
CanActivate๋ฅผ implementsํ๋ฉฐ Boolean ํ์์ ๋ฆฌํดํ๋ค.
โป ์ด ๊ณผ์ ์์ rest context์ gql context์ ํ์์ด ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ GqlExecutionContext๋ฅผ ์ฌ์ฉํด gql context๋ก ๋ณํ์์ผ์ค๋ค.
โ resolver์์ ๋ฐ๋ก @Context๋ก context ๋ฐ์์ gql context๋ก ๋ฐ๊พธ๊ณ return true, false ์ ์ธํ๋ ๊ฒ๊ณผ์ ์ฐจ์ด์ ?
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(context: ExecutionContext) {
const gqlContext = GqlExecutionContext.create(context).getContext();
const user = gqlContext['user'];
if (!user) {
return false;
}
return true;
}
}
@Query((returns) => User)
@UseGuards(AuthGuard)
me() {}
createParamDecorator๋ฅผ ์ฌ์ฉํด ๋ณ์๋ฅผ ์ ์ธํ๋ค.
// auth.decorator.ts ํ์ผ
export const AuthUser = createParamDecorator(
(data: unknown, context: ExecutionContext) => {
const gqlContext = GqlExecutionContext.create(context).getContext();
const user = gqlContext['user'];
return user;
},
);
@Query((returns) => User)
@UseGuards(AuthGuard)
me(@AuthUser() authUser: User) {
return authUser;
}
Dynamic module์ ์ ์ํ ๋ providers์ provide๊ฐ ์๋ฏธํ๋ ๊ฒ์?
@Module({})
@Global()
export class JwtModule {
static forRoot(options: JwtModuleOptions): DynamicModule {
return {
module: JwtModule,
exports: [JwtService],
providers: [
{
provide: CONFIG_OPTIONS,
useValue: options,
},
JwtService,
],
};
}
}
verify ํ ์ ์๋ ์๋ชป๋ token์ ์คฌ์ ๊ฒฝ์ฐ ๋ฐ์ํ๋ ์๋ฌ
์ค์ ํ๋ก๊ทธ๋จ ์์์๋ ์ด๋ฏธ ํ๋ก๊ทธ๋จ์์ ๊ฐ์ง๊ณ ์๋ token์ ์ฌ์ฉํด์ verifyํ๊ธฐ ๋๋ฌธ์ ๋ฐ์ํ ์ ์๋ ์๋ฌ์ด๋ค.
/playground์์ testํ ๋๋ง ๋ฐ์ํ๋ ์๋ฌ