본문 바로가기

프로젝트/미니 프로젝트

express + react 를 활용한 OAuth 소셜 회원가입및 로그인 진행하기 (1) - 백엔드 Sequelize 연동하기

반응형

express 를 기본 백엔드로 react를 기본 프론트엔드로 프로젝트를 구현 해야 할 일이 생겼다.

이에따라서 여러가지 자료들을 조합해 로그인 관리 방식을 고안해야 했고(주말에 쉴때 마다 고민했던거같다. 어떻게 로직을 짜야할까..? 여기저기 자료들도 찾아보고 하는데 꽤 시간이 들었다. ) 어느정도 결론이 나서 

토이프로젝트 식으로 작성해 본다. 

 

따라서 이에 따라 OAuth + JWT를 활용한 회원가입 및 로그인 방식을 구현해봤다.

활용할 로그인 방식은 구글 로그인으로 진행할 예정이며 카카오 로그인 또한 같이 설명에 넣을 예정이다.

https://loy124.tistory.com/384

https://loy124.tistory.com/385

 

 

express + react 를 활용한 OAuth 소셜 회원가입및 로그인 진행하기 (3) express 셋팅 및 Oauth 회원가입및

https://loy124.tistory.com/383 https://loy124.tistory.com/384    https://github.com/loy124/express-react-oauth-login GitHub - loy124/express-react-oauth-login: express 와 react를 활용해 만드는 ka..

loy124.tistory.com

 

https://github.com/loy124/express-react-oauth-login

 

GitHub - loy124/express-react-oauth-login: express 와 react를 활용해 만드는 kakao및 google 회원가입/로그인

express 와 react를 활용해 만드는 kakao및 google 회원가입/로그인. Contribute to loy124/express-react-oauth-login development by creating an account on GitHub.

github.com

 

DB 구조 

 

 

회원가입 방식

 

회원가입및 로그인 로직을 고려할 때 정말 많은 고민을 했다.

 

기존 Oauth로 인증된 ID와 DB에 저장된 ID가 일치하면 로그인 한다는 큰 그림을 그려놓고 

해당 인증이 성공했을 경우 어떠한 방식으로 jwt를 발급해서 어디에 저장해야하는지

고민이 들었다.

 

최종적으로 refreshToken의 위치는 cookie에 httpOnly 옵션을 줘서 저장하기로 하였고

accessToken의 위치는 프론트 단에서 변수로 받아온후 axios의 Authorizatioin에 Bearer 방식으로 넣어주기로하였다.

 

 

react(localhost:3001) 에서 backend(localhost:3000) 에 Ouath 요청 -> redirect 후 Code 발급 

-> 발급한 Code로 해당 소셜계정의 Access Token 발급 -> 해당 Access Token으로 이메일 정보 받아오기

-> 이메일 정보및 해당 소셜 아이디의 id를 DB에 저장 -> 로그인처리

 

로그인 처리 방식

Ouath 인증 -> 인증시 해당 sns_id와 DB의 sns_id가 일치하는지 여부 확인 -> 확인 후 refresh 토큰을 발급 후 redirect 할 코드에 cookie로 저장 

-> 프론트로 리다이렉트 -> 해당 프론트에서는 useEffect를 활용해 앱이 시작한 경우 accessToken을 요청하는 silent-refresh 비동기 axios 요청 -> refresh 토큰이 유효한 경우 accessToken 발급 -> accessToken은 Authorization header에 저장 

 

1. 백엔드 기초 준비

1. 기초 백엔드 준비 

 

npm init

npm init 명령어를 통해 해당 폴더에서 npm 을 활용할수 있도록 초기화시켜준다. 

 

 

 

그후 필요한 모듈들을 다운받아준다. 

npm i express cookie-parser cors dotenv jsonwebtoken mysql2 sequelize sequelize-cli axios

 

  • express
    • 대표적인 Node.js의 WEB 프레임워크
  • cookie-parser
    • 요청된 쿠키를 쉽게 추출할 수 있도록 도와준다.
  • cors
    • Cross Origin Issue에 대응하기 위해 사용하는 미들웨어
  • dotenv
    • process.env를 활용한 데이터 관리  
  • jsonwebtoken
    • 클라이언트와 서버 사이의 권한 인가를 위해 사용하는 토큰 
  • mysql2
    • node에서 mysql과 연결할수 있게 도와주는 커넥터 
  • sequelize, sequelize-cli
    • 데이터베이스와의 연동을 객체지향석으로 해석해서 사용 할 수 있다. 
  • axios
    • 대표적인 비동기 통신 요청 API

 

 

이제 sequelize-cli를 활용해 폴더구조를 구축해준다.

npx sequelize-cli init

위와같이 init을 구축하게 되면 

 

 

기초 폴더 셋팅이 완성된다.

 

이제 config -> config.json에 접속해 

 

mysql에 접속할때의 username과 password 사용하려는 DB 또한 선택해 준다 .

 

 

{
  "development": {
    "username": "root",
    "password": "root",
    "database": "oauth-login-system",
    "host": "127.0.0.1",
    "dialect": "mysql"
  },
  "test": {
    "username": "root",
    "password": null,
    "database": "database_test",
    "host": "127.0.0.1",
    "dialect": "mysql"
  },
  "production": {
    "username": "root",
    "password": null,
    "database": "database_production",
    "host": "127.0.0.1",
    "dialect": "mysql"
  }
}

 

 

 

이제 해당 database 이름으로 mysql에 스키마를 생성한다 

 

(시퀄라이즈에 대한 설명은 하단 블로그에 기재되어있다)

https://loy124.tistory.com/373?category=803819 

 

Node Sequelize ORM 다루기 - DB 생성및 테이블 생성하기

Sequelieze는 Node에서 사용하는 ORM이다. 여기서 ORM 이란? ORM은 Object Relational Mapping의 약자로써 OOP(Object Oritented Programming)에서 객체로 구현한 부분을 DB와 자동으로 매핑해주는 것을 의미해준..

loy124.tistory.com

npx sequelize db:create

 

 

이제 sequelize 셋팅이 완료되었다면 이제 테이블을 생성한다. 

DB 구조 

DB구조는 다음과 같다 

users에는 user에 대한 정보를 기록하고

social_logins에는 해당 user가 연동한 sns type과 해당 sns의 고유 id 정보를 기록한다. 

 

먼저 users에 대한 테이블 정의부터 진행한다

 

npx sequelize model:generate --name user --attributes email:string,password:string,phone_number:string,nickname:string,introduce:string,profile:string,type:integer,email_authentication:boolean

그후 social_logins에 대한 정의 또한 진행한다.

 

npx sequelize model:generate --name social_login --attributes type:string,sns_id:string

이제 두 모델을 정의했으니 

 

외래키 추가 + 관계형 mapping이 남았다.

 

외래키 추가를 위해 migration 파일을 하나 생성해준다. 

npx sequelize migration:generate --name fk_social_login

2021~fk_social_login.js

 

'use strict';
// 외래키 추가하기 
module.exports = {
  up: async (queryInterface, Sequelize) => {
    await queryInterface.addColumn("social_logins", "user_id", {
      type: Sequelize.INTEGER,
      references:{
        model:{
          tableName:'users'
        },
        key:'id'
      },
      allowNull:false,
      onDelete: "cascade",
      onUpdate: "cascade",
    });
  },

  down: async (queryInterface, Sequelize) => {
    await queryInterface.removeColumn("social_logins", "user_id");
  }
};

외래키를 추가해주는 migration파일을 수정해준다. 

 

마지막으로 models 에 각각 관계형 매핑을 해주면 끝이난다. 

 

models/user.js

'use strict';
const {
  Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
  class user extends Model {
    /**
     * Helper method for defining associations.
     * This method is not a part of Sequelize lifecycle.
     * The `models/index` file will call this method automatically.
     */
    static associate(models) {
      // define association here
      // user: social_login은 1대 N 관계이다 
      // 외래키인 user_id 컬럼이 현재 User의 id 컬럼을 참조하고 있음
      models.user.hasMany(models['social_login'],{foreignKey:'user_id'})
    }
  };
  user.init({
    email: DataTypes.STRING,
    password: DataTypes.STRING,
    phone_number: DataTypes.STRING,
    nickname: DataTypes.STRING,
    introduce: DataTypes.STRING,
    profile: DataTypes.STRING,
    type: DataTypes.INTEGER,
    email_authentication: DataTypes.BOOLEAN
  }, {
    sequelize,
    modelName: 'user',
  });
  return user;
};

 

models/social_login.js

 

'use strict';
const {
  Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
  class social_login extends Model {
    /**
     * Helper method for defining associations.
     * This method is not a part of Sequelize lifecycle.
     * The `models/index` file will call this method automatically.
     */
    static associate(models) {
      // define association here
        // 해당 컬름의 user_id가 User의 id 컬럼을 참조하고 있음
        models['social_login'].belongsTo(models.user,{foreignKey:'user_id'})
    }
  };
  social_login.init({
    type: DataTypes.STRING,
    sns_id: DataTypes.STRING
  }, {
    sequelize,
    modelName: 'social_login',
  });
  return social_login;
};

 

이제 마지막으로

 

migrations 폴더내에있는 파일들을 통해 db와 일치화  작업을 해주면 DB 셋팅은 마무리된다. 

 

npx sequelize db:migrate

 

 

이제 workbench등 DB 테이블을 조회해보면 성공적으로 

해당 테이블이 추가된 것을 확인할 수 있다.

 

https://loy124.tistory.com/384

 

 

참고자료 

https://hazel-developer.tistory.com/81

https://velog.io/@yaytomato/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%90%EC%84%9C-%EC%95%88%EC%A0%84%ED%95%98%EA%B2%8C-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EC%B2%98%EB%A6%AC%ED%95%98%EA%B8%B0

반응형