@UseGuards(AuthGuard)를 사용해서 User가 있을 때에만 접근가능하도록 해주었다.
이번에는 Metadata를 사용해보자. 여기서 Metadata를 사용하는 이유는 사용자의 role에 따라 접근하도록 하기 위함이다.
@SetMetadata를 사용하는데 여기에는 2개의 인자를 가질 수 있다.
하나는 key이고 다른 하나는 value이다.
@SetMetadata("role", UserRole.Owner)
핵심은 모든 resolver에서 metadata를 사용하는데 있다.
그러기 위해서 auth 아래에 auth.decorator.ts를 만들어서 사용한다.
함수형을 만들고 여기에 전달하는 인자는 UserRole을 enum 형태로 export 하여 만든다.
type AllowedRoles = keyof typeof UserRole | "Any";
아래는 UserRole enum이다.
export enum UserRole {
Client = 'CLIENT',
Owner = 'OWNER',
Delivery = 'DELIVERY',
}
코드는 아래와 같다.
import { SetMetadata } from '@nestjs/common';
import { UserRole } from 'src/users/entities/user.entity';
type AllowedRoles = keyof typeof UserRole | "Any";
export const Role = (roles: AllowedRoles[]) => SetMetadata('roles', roles);
user.resolvers.ts에서 me를 보려면 Role이 어떤것이든지 상관 없다고 나오도록 한다.
@Query(returns => User)
@Role(['Any'])
me(@AuthUser() authUser: User) {
return authUser;
}
auth.module.ts는 아래와 같다.
import { Global, Module } from '@nestjs/common';
import { APP_GUARD } from '@nestjs/core';
import { AuthGuard } from './auth.guard';
@Module({
providers: [
{
provide: APP_GUARD,
useClass: AuthGuard,
},
],
})
export class AuthModule {}
auth.guard.ts는 아래와 같다.
import { UseGuards } from '@nestjs/common';
import { Resolver, Query, Mutation, Args } from '@nestjs/graphql';
import { AuthUser } from 'src/auth/auth-user.decorator';
import { Role } from 'src/auth/auth.decorator';
import { AuthGuard } from 'src/auth/auth.guard';
import {
CreateAccountInput,
CreateAccountOutput,
} from './dtos/create-account.dto';
import { EditProfileInput, EditProfileOutput } from './dtos/edit-profile.dto';
import { LoginInput, LoginOutput } from './dtos/login.dto';
import { UserProfileInput, UserProfileOutput } from './dtos/user-profile.dto';
import { VerifyEmailInput, VerifyEmailOutput } from './dtos/verify-email.dto';
import { User } from './entities/user.entity';
import { UserService } from './users.service';
@Resolver(of => User)
export class UserResolver {
constructor(private readonly usersService: UserService) {}
@Mutation(returns => CreateAccountOutput)
async createAccount(
@Args('input') createAccountInput: CreateAccountInput,
): Promise<CreateAccountOutput> {
return this.usersService.createAccount(createAccountInput);
}
@Mutation(returns => LoginOutput)
async login(@Args('input') loginInput: LoginInput): Promise<LoginOutput> {
return this.usersService.login(loginInput);
}
@Query(returns => User)
@Role(['Any'])
me(@AuthUser() authUser: User) {
return authUser;
}
@Query(returns => UserProfileOutput)
@Role(['Any'])
async userProfile(
@Args() userProfileInput: UserProfileInput,
): Promise<UserProfileOutput> {
return this.usersService.findById(userProfileInput.userId);
}
@Mutation(returns => EditProfileOutput)
@Role(['Any'])
async editProfile(
@AuthUser() authUser: User,
@Args('input') editProfileInput: EditProfileInput,
): Promise<EditProfileOutput> {
return this.usersService.editProfile(authUser.id, editProfileInput);
}
@Mutation(returns => VerifyEmailOutput)
verifyEmail(
@Args('input') { code }: VerifyEmailInput,
): Promise<VerifyEmailOutput> {
return this.usersService.verifyEmail(code);
}
}
코드 대로 localhost:3000/graphql에서 me를 실행하면 X-JWT가 없을 때 resource를 찾을 수 없다는 것을 볼 수 있고 guard가 잘 작동됨을 알 수 있다.
'Uber Eats' 카테고리의 다른 글
Uber Eats # 19 Mail module 만들기 (0) | 2021.03.19 |
---|---|
Uber Eats # 18 User Profile (0) | 2021.03.13 |
Uber Eats # 17 AuthGuard (0) | 2021.03.13 |
Uber Eats # 16 User Authentication (0) | 2021.03.11 |
Uber Eats # 15 User Resolver and Service, InputType과 ObjectType 비교 (0) | 2021.03.09 |