Develop/GraphQL

[GraphQL] passport로 인증기능 만들기

안다희 2020. 3. 23. 00:58
728x90

server.js

require("dotenv").config();

import logger from "morgan"; // 필요한지 잘 모르겠지만
import "./passport";
import passport from "passport";
// import { ApolloServer } from "apollo-server-express"; // 이걸로 하면 request context에 제대로 안날아옴
import { GraphQLServer } from "graphql-yoga";
import schema from "./schema";
import { authenticateJwt } from "./passport";
import express from "express";
import { isAuthenticated } from "./utils";

const PORT = process.env.PORT || 4000;

const server = new GraphQLServer({
  schema,
  context: ({ request }) => ({ request, isAuthenticated })
});

// 이렇게 하면 context에 request가 안날아옴
// const app = express();
// server.applyMiddleware({ app });
// app.listen({ port: PORT }, () => {
//   console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`);
// });
// app.use(logger("dev"));
// app.use(authenticateJwt);

// express 서버에 접근. logger 미들웨어를 사용하도록 할거야. 사실은 모건 모듈이지.
server.express.use(logger("dev"));
server.express.use(authenticateJwt);

server.start({ port: PORT }, () => {
  console.log(`🚀 Server running on http://localhost:${PORT}`);
}); // port: dotenv config에서 포트 읽어오도록 할 수 있어

 

passport.js

import { ExtractJwt, Strategy } from "passport-jwt";
import passport from "passport";
import { prisma } from "../generated/prisma-client";
require("dotenv").config();

const jwtOpts = {
  jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), // Authorization 헤더에서 jwt 찾는 역할
  secretOrKey: process.env.JWT_SECRET
};

// 토큰을 암호화하기 위한 문자열 = secret
// { id: 1 } 이런 사용자 정보가 암호화되어서 토큰에 담겨. JWT는 토큰을 입력받아서 정보 해석하고 해석된 정보를 콜백함수로 전달해줘.
// verifyUser 함수 만들자.
// 확인용 callback 함수도 추가. 옵션이 잘 맞게 적용되었을 때 JwtStrategy 함수가 토큰을 해석할거야.
// 우리가 사용자 찾았을 때 호출하는 함수야.
// user를 payload의 정보로 찾을 수 있어야 해.

const verifyUser = async (payload, done) => {
  try {
    const user = await prisma.user({ id: payload.id });
    if (user !== null) {
      return done(null, user);
    } else {
      return done(null, false);
      // or create a new account. 토큰에 id가 있고 사용자가 없다면 계정을 생성해도 되지!
    }
  } catch (error) {
    return done(error, false);
  }
};

export const authenticateJwt = (req, res, next) =>
  passport.authenticate("jwt", { session: false }, (error, user) => {
    console.log("🧣", user);
    if (user) {
      req.user = user;
    }
    next();
    // express에서는 미들웨어를 지나서 라우트가 실행돼. 토큰을 받아서 해석,사용자찾고 사용자 존재하면 req객체에 사용자 추가하고 나면 graphql 함수를 실행하는거야.
    // 로그인 되어 있다면 모든 gql 요청에 사용자 정보가 추가되어서 요청되는거지.
  })(req, res, next); // 함수가 리턴되는거야. Fn(req, res, next) 인거야. 이경우에는 실행해야 하는 함수가 gql 함수래. (?)

passport.use(new Strategy(jwtOpts, verifyUser));
passport.initialize();

 

.env // 이건 어디서 왔지?

JWT_SECRET="hjPedyU7yOHWm07BbP0ubJXzEt6XnGZW"

 

utils.js

require("dotenv").config();
import jwt from "jsonwebtoken";

export const generateToken = id => jwt.sign({ id }, process.env.JWT_SECRET);

export const isAuthenticated = request => {
  console.log("1");
  console.log("7");
  console.log("7", !request.user);
  if (!request.user) {
    console.log("21");
    throw Error("You need to log in to perform this action");
  }
};

 

generatedToken은 회원가입 할 때 넣으면 되겠지.

 

getUser.js

import { prisma } from "../../../../generated/prisma-client";

export default {
  Query: {
    getUser: (_, __, { request, isAuthenticated }) => {
      isAuthenticated(request);
      return prisma.user({ id: request.user.id });
    }
  }
};

 

 

 

클라에서 보낼 땐 

const client = new ApolloClient({
  cache,
  uri: 'http://localhost:4000',
  typeDefs, // 로컬상태
  resolvers, // 로컬상태
  request: async operation => {
    // 이 함수가 리턴하는 값은 요청마다 추가도ㅔㅐ. 이함수가 매 요청마다 호출되는거지.
    // 매 요청을 중간에 가로채는거야.
    const token = await AsyncStorage.getItem('jwt');
    console.log('👨‍❤️‍💋‍👨', token);
    return operation.setContext({
      // 요청마다 이 함수가 실행돼.
      headers: {Authorization: `Bearer ${token}`},
    });
  },
});

 

 

'Develop > GraphQL' 카테고리의 다른 글

GQL서버 init  (0) 2020.04.10
[GraphQL] apollo-server와 express 연결하기  (0) 2020.03.22
[GraphQL / Apollo] 도입해보기  (0) 2020.03.02
[GraphQL / Apollo] 오프라인 노트앱 만들기  (0) 2020.02.16