본문 바로가기

백엔드/Serverless

[인스타그램 클론코딩] 사용자 인증 & GraphQL Context 활용

Cognito ID 토큰 복호화 포스트에서 클라이언트에서 보낸 토큰을 복호화해서 userName, 이메일, 토큰 유효성을 얻을 수 있었습니다.

 

이때 ApolloServer 생성자의 context 속성(함수)을 사용했었는데요. 여기서 context가 반환한 객체는 GraphQL의 모든 Resolvers가 공유할 수 있습니다. 

 

아직 GraphQL, Resolver가 뭐지 모른다면? 추천: 나의 첫번째 GraphQL서버 만들기

handler.js

const server = new ApolloServer({
  schema,
  context: async ({ event, context }) => {
    const authorization = event.headers.authorization || event.headers.Authorization;
    const {userName, isValid} = await verifier({token: authorization}); // 토큰 유효성 확인
    const me = await prisma.user.findOne({ where: { userName }});
    return { prisma, me, isValid } // 모든 Resolvers가 공유 가능
  }
});

addComment.js (Resolver)

인스타크램 클론코딩 GraphQL 백앤드에 사용된 Resolvers 중 하나입니다. 세 번째 매개변수로 ApolloServer 생성자의 context에서 반환한 객체를 얻을 수 있습니다.

 

isValid가 true가 아니면, 즉, 클라이언트에서 전송한 토큰을 Cognito에서 확인한 결과 유효한 사용자가 아니면(로그인한 사용자가 아니면) Resolver는 더 이상 작업을 수행하지 않고 오류를 반환합니다.

const _default = {
    Mutation: {
        addComment: async (_, args, { prisma, me, isValid }) => {
            if(isValid !== true) throw Error("NotAuthenticated");
            /* Comment를 추가하는 작업 추가 */
        }
    }
}

exports.default = _default;

참고로 userName과 이메일은 사용자가 Cognito를 통해 가입할 때 데이터베이스의 사용자 테이블에 복제되었었습니다.

참조: [인스타그램 클론코딩] Cognito Pre-SignUp 람다 함수

 

또한 나중에 설명하겠지만 데이터베이스에서 사용자(User)의 userName이메일유니크(유일한) 속성으로 지정해 두었습니다. 

 

따라서 Cognito로 부터 얻은 userName 또는 이메일을 통해서 데이터베이스의 사용자 정보에 접근할 수 있습니다. 일단은 userName을 사용해서 사용자 정보를 얻어오는 코드라고만 알아두고, Prisma에 대해서는 나중에 더 자세히 설명하겠습니다.

const me = await prisma.user.findOne({
    where: {
       userName
    }
});

 

저의 경우는 me가 다음과 같이 출력됩니다. 참고로 여기서 사용되는 것은 id입니다. 이 id를 사용해서 사용자가 작성한 포스트(Post)나 사용자와 연결된 다른 사용자에 접근할 수 있습니다. 그래서 User 객체(me)도 context에 넣어줍니다. 

{
    id: 35,
    userName: 'joondong',
    avatar: '<이미지>',
    email: '<이메일>',
    firstName: '준동',
    lastName: '권',
    name: '',
    bio: '',
    createdAt: 2020-05-06T02:14:10.000Z,
    updatedAt: 2020-05-06T02:14:09.812Z
}

참고: https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client/field-selection#select