[Back-End] 회원가입, 로그인 with GraphQL

박성수·2023년 2월 7일
0
post-thumbnail

기존에 프론트엔드에서는 회원가입, 로그인 값들을 저장해둔 다음 POST요청을 보내기만 하면됐다..
로그인이라면 토큰을 받아서 로컬스토리지에 저장을 해주면 됐는데,,

개인프로젝트를 진행하면서 백쪽에서 회원가입, 로그인을 구현해보니 백쪽에서는 꽤 까다로운 절차가 있었다.

  1. 프론트에서 회원가입 정보를 받는다.
  2. 백쪽에서는 받은 정보를 바탕으로 DB에 저장한다. 비밀번호를 hash처리해서 저장.
  3. 프론트에서 로그인 정보를 받는다.
  4. 받은 email이 DB에 일치하는 정보가 있는지 확인한다.
  5. DB에 일치하는 정보가 있다면 받은 비밀번호와 hash처리된 비밀번호가 일치하는지 검증한다.
  6. 일치한다면 jwt를 발행.

Bcrypt

비밀번호를 hash처리하기 위해 솔팅(salting)과 키스트레칭(keystretching)를 활용하여 단방향 암호와를 하는 라이브러리이다.

이번 프로젝트에서 비밀번호 저장을 위해 사용하였다.

  1. 설치
npm i bcrypt
  1. 기본사용법
import bcrypt from "bcrypt"


//해쉬 처리
const hashedPassword = bcrypt.hash(평문 비밀번호, Cost Factor) //CostFactor란 key stretching의 수

//검증
bcrypt.compare(받은 비밀번호, hashedPassword)

JWT

JSON Web Token은 클라이언트와 서버간 정보를 JSON의 형태로 안전하게 전송하기 위한 개방형 표준이다.
자세한 내용은 다음에 더 알아보도록...

  1. 설치
npm i jsonwebtoken
  1. 기본사용법

토큰화는 sign 메서드, 검증은 verify메서드를 활용한다.

import jwt from "jsonwebtoken"

const token = jwt.sign({email : "" , password : ""} , secretKey) // 토큰화

const verify = jwt.verify(token, secretKey) //토큰 검증

1) sign
sign메서드에서는 첫 번째 인자로 토큰으로 전달할 내용들이 들어간다. 두 번째 인수로 secret key가 들어가는데 노출되지 않도록 환경변수로 관리해 줘야한다.
세 번째 인수로 token의 옵션을 설정할 수 있고 옵션이 들어가지 않으면 HS256 알고리즘으로 JWT가 발급된다.

2) verify
verify메서드는 첫 번째 인자로 토큰이 들어가고 두 번째 인자로 토큰을 발급할 때 썼던 secretkey가 들어간다.

GraphQL 회원가입 로그인 API 코드

//GraphQL mutation 타입정의

type Auth {
    token: String
    User: User
  }

  type User {
    id: Int!
    user_name: String!
    email: String!
    password: String!
    nickname: String!
  }

type Mutation {
    signup(
      id: Int
      user_name: String!
      email: String!
      password: String!
      nickname: String!
    ): User

    login(email: String!, password: String!): Auth
  }

1. 회원가입

회원가입 resolvers

const resolvers = {
	Mutation : {
    	signup: async(_parent, { email, password, nickname, user_name }, _ctx) => {
        	const hashPassword = await bcrypt.hash(password, 12); 
          	//받은 정보의 비밀번호를 hash처리 한다.
      		await client.User.create({data: { email, nickname, user_name, password: hashPassword }, 
			// 받은정보를 User DB에 저장하고 비밀번호만 Hash처리해서 저장.
      });
        }
    }
}

2. 로그인

로그인 resolvers

const resolvers = {
  Mutation: {
    login: async (_parent, { email, password }, _ctx) => {
      const loginUser = await client.User.findUnique({
        where: {
          email,
        },
      });
      //로그인시 받은 정보를 바탕으로 prisma에서 유저 email정볼르 찾는다.
      if (!loginUser) {
        throw new Error("등록되지 않은 이메일입니다.");
      }
      //만약 db에 저장되지 않은 email이라면 오류 반환
      const passwordMatch = await bcrypt.compare(password, loginUser.password);
      // 받은 유저 정보의 비밀번호와, db에 저장된 hash처리된 비밀번호를 검증한다.
      if (!passwordMatch) {
        throw new Error("비밀번호가 일치하지 않습니다.");
      }
      // 일치하지 않다면 오류반환
      const token = jwt.sign(
        {
          email: loginUser.email,
          password: loginUser.password,
        },
        process.env.SECRET_KEY
      );
      //일치한다면 jwt를 발급
      return { token, loginUser };
    },
  },
};
profile
Front-end Developer

0개의 댓글