티스토리 뷰

기술 스택 : GraphQL, mongoDB, mongoose

 

1. directive.ts

class AuthDirective extends SchemaDirectiveVisitor {
    1) 해당 페이지에서 요구되는 타입 확인 (requires)
    2) 해당 페이지에서 요구되는 타입(User)의 토큰을 가져온다. (userToken)
         1-1) 토큰이 없으면 인증 x
    3) 토큰을 복호화한 후 사용자를 조회 (인증) 
         2-1) 조회 결과 없으면 인증 x
    4) 인증이 되면, 인증 성공

 

2. app.ts

const apolloServer = new ApolloServer({
    schemaDirectives: {
    	 auth: AuthDirective
    }
})

 

3. schema.ts

directive @auth(requires: USER!) on FIELD_DEFINITION

- @auth로 사용가능


4. front에서 라우팅 처리


- 인증을 두번 해야하는 경우

// ex)
type Query {
    users: String
    isAuthorizedUser: Boolean 
     	@hasRole(roles: [THIS_ADMIN, THIS_SUPER_ADMIN] @auth(requires: USER)
        // auth가 먼저 실행되고 hasRole이 실행됨 -> 오른쪽부터 왼쪽으로
}

 

5. 적용 결과

import { SchemaDirectiveVisitor } from 'apollo-server-express';
import { defaultFieldResolver } from 'graphql';
import jwt from 'jsonwebtoken';
import Config from '../../config';

class AuthDirective extends SchemaDirectiveVisitor {
  visitFieldDefinition(field) {
    const requiredRole = this.args.requires;
    const { resolve = defaultFieldResolver } = field;
    // resolve: isAuthorizedUser

    field.resolve = async (...args) => {
      try {
        const { req, res, dataSources } = args[2]; // context
        const [token, type] = [req.signedCookies.userToken, 'User'];
        if (!token) throw new Error('Unauthorized access'); // 인증 실패 시 처리 -> catch (err)

        const decoded = jwt.verify(token, Config.JWT_SECRET);
        const model = dataSources.model(type);
        const result = await model.findOne({ _id: decoded.id });
        if (result) return resolve.apply(this, args);
        else {
          throw new Error('You must be the authenticated');
        }
      } catch (err) {
        // 인증 실패 시 로직
      }
    };
  }
}
export default AuthDirective;
공지사항
최근에 올라온 글
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함