TypeGraphQL[4] - Authorization

해당 포스트는 Ben Awad의 TypeGraphQL Tutorial을 기반으로 작성하였습니다.

Authorization이란 ?

Authorization From Wikipedia

In contrast with identification, the act of indicating a person or thing’s identity, authentication is the process of verifying that identity.

어떤 리소스에 access가 가능한지를 검증하는 기능을 말한다.

web에서 authrization은 예를 들어서, 로그인을 해야 접근할 수 있는 경로가 있다면, 그 경로는 Authorization이 필요하다.

어떤 경로의 접근을 제한하고 특정 자격을 지닌 유저만 접근 가능하도록 하는 것이 Authorization이다.

TypeGraphQL로 Authorization 구현하기

방법 1. @Authorized() 데코레이터와 authChecker 함수

TypeGraphQL - Authorization

@Authorized()

먼저 Auth가 필요한 곳에 @Authorized() 데코레이터를 추가해준다. Object type이나 resolver의 query나 mutation에 적용 가능하다.

// Object type에 적용
@ObjectType()
class MyObject {
  @Field()
  publicField: string;

  @Authorized()
  @Field()
  authorizedField: string;

  @Authorized("ADMIN") // 인자를 통해 Role 추가
  @Field()
  adminField: string;

  @Authorized(["ADMIN", "MODERATOR"])
  @Field({ nullable: true })
  hiddenField?: string;
}

Authorized user는 publicFieldauthorizedField를 읽을 수 있다. 하지만 adminFieldhiddenField는 읽을 수 없다.

// resolver에 적용

@Resolver()
export class RegisterResolver {
  @Authorized() // auth가 필요한 query임을 알린다.
  @Query(() => String)
  async hello() {
    return "hello";
  }
  
  // 생략 ..
}

schema에 authChecker함수 추가

authChecker 함수는 실제로 Authorization로직을 구현하는 함수다. buildSchema를 다음과 같이 수정하자.

// index.ts

const schema = await buildSchma({
    resolvers: [MeResolver, RegisterResolver, LoginResolver]
    authChecker: ({context: {req}}) => {
        // session에 userId값이 있다면 access 가능
        if (req.session.userId) {
            return true
        }
        return false
    }
})

이제 로그인하지 않고 hello 쿼리를 요청하면 error가 발생한다.

{
    hello
}

방법 2. 미들웨어

TypeGraphQL - middleware

미들웨어를 만들고 등록하여 특정 필드나 쿼리에 접근하기 전에 Authorization을 수행할 수 있다.

Creating Middleware

미들웨어는 기본적으로 함수이며 다음 두 가지 파라미터를 가진다.

미들웨어를 따로 관리하기 위해 middlewares 폴더를 먼저 생성한다.

logger middleware

resolverData를 logging하는 간단한 미들웨어를 만든다.

// src/modules/middlewares/logger.ts

export const logger: MiddlewareFn = async (data, next) => {
    console.log(data)
    return next()
}

MiddlewareFn 타입을 이용하여 미들웨어 함수를 만든다.

isAuth middleware

Authorization을 수행하는 미들웨어를 만든다.

// src/modules/middlewares/isAuth.ts

// req에 접근하기 위해 제네릭타입을 MyContext로 설정한다.
export const isAtuh: MiddlewareFn<MyContext> = async ({context}, next) => {
    if (!context.req.session.userId) {
        throw new Error("Not authorized");
    }
    return next()
}

미들웨어 등록하기

@Authrized() 를 지우고 @UseMiddleware()를 추가한다.


    @UserMiddleware(logger, isAuth)
    @Query(() => String)
    async hello() {
        return "hello"
    }

로그인하지 않고 hello를 쿼리할 경우 Not authorized 메세지와 함께 에러가 발생할 것이다.