반응형

이 글의 동영상 강좌

https://youtu.be/P9fvgGHd_Jg

Backend의 Nestjs에서 Database(MySQL)를 연결하기 위해 TypeORM을 설정해봅니다.

 

진행 순서는 다음과 같습니다.

MySQL Schema와 User 생성

MySQL Workbench를 이용해서 Schema와 User를 생성합니다.

- Schema : slider

- User : slider

- Password : 1234

자세한 내용은 이전에 작성한 내용을 참조하시기 바랍니다.

https://codegear.tistory.com/32

 

데이터베이스기초-02.MySQL-Schema, User, Table 생성하기

이 글의 동영상 강의입니다. https://youtu.be/hOOiqk8Z1gQ MySQL Workbench를 이용하여 가장 기본적인 Schema와 User를 생성하고, User에게 Schema의 권한을 주는법과, Schema에 Table을 생성하는 법을 알아보겠..

codegear.tistory.com

 

패키지 설치

TypeORM과 MySQL 패키지를 설치합니다.

yarn add @nestjs/typeorm typeorm mysql2

 

TypeORM 설정

/src/orm.config.ts 파일을 아래와 같이 생성합니다.

import { TypeOrmModuleOptions } from '@nestjs/typeorm';

function ormConfig(): TypeOrmModuleOptions {
  const commonConf = {
    SYNCRONIZE: false,
    ENTITIES: [__dirname + '/domain/*.entity{.ts,.js}'],
    MIGRATIONS: [__dirname + '/migrations/**/*{.ts,.js}'],
    MIGRATIONS_RUN: false,
  };

  return {
    name: 'default',
    type: 'mysql',
    database: process.env.DB_NAME,
    host: process.env.DB_HOST,
    port: Number(process.env.DB_PORT),
    username: process.env.DB_USER,
    password: process.env.DB_PASS,
    logging: true,
    synchronize: commonConf.SYNCRONIZE,
    entities: commonConf.ENTITIES,
    migrations: commonConf.MIGRATIONS,
    migrationsRun: commonConf.MIGRATIONS_RUN,
  };
}

export { ormConfig };

 

Main Module에 typeorm config 설정 추가

/src/app.module.ts에서 @Module -> imports 아래에 다음 내용을 추가합니다.

....
import { TypeOrmModule } from '@nestjs/typeorm';
import { ormConfig } from './orm.config';

@Module({
    imports: [
    	TypeOrmModule.forRootAsync({ useFactory: ormConfig }),
    ]
....

 

환경 설정 파일(.env) 생성

orm.config.ts에서 process.env.DB_NAME과 같은 형태로 환경변수를 참조하도록 했습니다.

/.env 파일을 아래와 같이 생성합니다.(.env는 dotenv라고 읽습니다.)

NODE_ENV=local
DB_HOST=localhost
DB_PORT=3306
DB_USER=slider
DB_PASS=1234
DB_NAME=slider

- local db에 설정한데로 값을 입력하면 됩니다.

 

@nestjs/config 모듈 추가

.env 파일을 사용하기 위해서는 dotenv모듈이 필요합니다.
nestjs에서는 @nestjs/config 모듈을 설치하면 dotenv모듈을 사용할 수 있습니다.

아래와 같이 설치를 합니다.

yarn add @nestjs/config

아래와 같이 main module에 ConfigModule 관련 설정을 추가합니다.

/src/app.module.ts

import { ConfigModule } from '@nestjs/config';
...

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true
    }),
    ....]
...

 

로그 확인

이제 application을 실행해봅니다.

yarn start

application이 정상적으로 실행되면 아래와 같은 로그를 확인할 수 있습니다.

 

Entity 생성

위에서 typeorm 설정 파일의 entity 파일 위치를 아래와 같이 설정했습니다.

ENTITIES: [__dirname + '/domain/*.entity{.ts,.js}'],

따라서 src/domain이라는 폴더를 만들고 entity 파일들을 만들면 됩니다.

 

/src/domain/user.entity.ts 를 아래와 같이 만듭니다.

import { Column, Entity, PrimaryGeneratedColumn, OneToMany } from 'typeorm';
import {UserAuthority} from "./user-authority.entity";

@Entity('user', { schema: 'slider' })
export class User {
    @PrimaryGeneratedColumn({ type: 'int', name: 'id' })
    id: number;

    @Column('varchar', { name: 'kakao_id', length: 45 })
    kakaoId: string;

    @Column('varchar', { name: 'email', length: 100 })
    email: string;

    @Column('varchar', { name: 'name', nullable: true, length: 45 })
    name: string | null;

    @Column('varchar', { name: 'gender', length: 10 })
    gender: string;

    @Column('varchar', { name: 'phone', length: 20 })
    phone: string;

    @Column('varchar', { name: 'birth', length: 10 })
    birth: string;

    @Column('varchar', { name: 'profile_image', nullable: true, length: 200 })
    profileImage: string | null;

    @Column('timestamp', {
        name: 'created_at',
        nullable: true,
        default: () => 'CURRENT_TIMESTAMP',
    })
    createdAt: Date | null;

    @Column('timestamp', {
        name: 'updated_at',
        nullable: true,
        default: () => 'CURRENT_TIMESTAMP',
    })
    updatedAt: Date | null;

    @OneToMany(() => UserAuthority, (userAuthority) => userAuthority.user, {
        eager: true,
    })
    authorities?: any[];
}

/src/domain/user-authority.entity.ts를 다음과 같이 만듭니다.

import {
  Column,
  Entity,
  JoinColumn,
  ManyToOne,
  PrimaryGeneratedColumn,
} from 'typeorm';
import { User } from './user.entity';

@Entity('user_authority')
export class UserAuthority {
  @PrimaryGeneratedColumn()
  id: number;

  @Column('int', { name: 'user_id' })
  userId: number;

  @Column('varchar',{name: 'authority_name'})
  authorityName: string;

  @ManyToOne(() => User, (user) => user.authorities)
  @JoinColumn({ name: 'user_id', referencedColumnName: 'id' })
  user: User;
}

 

테이블 자동 생성

orm.config.ts 파일에서 syncronize를 true로 변경합니다.

SYNCRONIZE: true,

 

Application을 실행합니다.

yarn start

MySQL에 테이블이 생성된 것을 확인할 수 있습니다.

 

이상으로 TypeORM 설정이 완료되었습니다.

반응형
반응형

다음은 이 글의 동영상 강좌입니다.

https://youtu.be/9KbnFR_1_Jg

 

 

 

nest project 생성(Backend)

nestjs.com에 가시면 프로젝트 생성하는 법을 확인할 수 있습니다.

https://docs.nestjs.com/first-steps

- project명은 slider-api로 생성합니다.

nest new slider-api

 

nuxt project 생성(Frontend)

nuxt.org에 가시면 프로젝트 생성하는 법을 확인할 수 있습니다.

https://nuxtjs.org/docs/get-started/installation

 

Installation

Here, you will find information on setting up and running a Nuxt project in 4 steps.

nuxtjs.org

- project명은 slider-front로 생성합니다.

- yarn create nuxt-app <project-name> 을 사용합니다.

 

yarn create nuxt-app slider-front

 

Repository 생성

github.com에 접속해서 Repository를 생성합니다.

  • github.com -> Repositories -> New를 선택합니다.
  • Backend Repository는 slider-api로 생성합니다.
  • Frontend Repository는 slider-front로 생성합니다.

.gitignore 파일 생성

  • 두개 프로젝트의 root 폴더에 .gitignore 파일을 생성합니다.
  • 이 파일은 git 서버에 올라가지 않아도 되는 파일들을 작성해줍니다.
/node_modules
/dist

.DS_Store
.idea

yarn.lock

 

Repository 연결

  • github desktop을 이용해서 소스를 clone합니다.
  • clone한 소스에 생성한 프로젝트 소스를 이동합니다.
  • 소스를 commit하고 push 합니다.

 

반응형
반응형

그동안 배웠던 내용들을 이용해서 사이트를 만드는 강좌를 진행합니다.

제목은 Nodejs와 Vuejs로 사이트 만들기 입니다.

 

이 글의 동영상 강좌입니다.

https://youtu.be/9RBeK3U8Z5Y

개발 스펙은 다음과 같습니다.

  • Backend는Nodejs (Nestjs 프레임워크를 사용합니다. TypeORM을 통해 DB를 연동합니다.)
  • Frontend는 Vuejs (Nuxtjs 프레임워크를 사용합니다.)
  • Database는 MySQL을 사용합니다. (MySQL Workbench의 Model 기능을 사용합니다.)

인프라는 다음과 같이 구성합니다.

  • Version Control(코드 저장소)은 Github을 사용합니다.
  • Production(운영) Server는 AWS의 EC2를 사용합니다.
  • Image가 배포될 Server는 AWS의 S3를 사용합니다.

기타

  • 배포는 Github Actions를 이용해서 자동배포가 되도록 구성을 합니다.
  • 로그인 및 회원 가입은 카카오 로그인을 이용해서 처리합니다.

기능

  • 사이트의 첫화면에 Slideshow가 나타나며 자동 스크롤이 됩니다.
  • 이 이미지는 관리자를 통해 관리되도록 합니다.

사이트를 직접 만들면서 각종 기술들이 어떻게 쓰이는지를 알아 갈 수 있도록 하는것이 이 강좌의 목적입니다.

많이 기대해주세요^^

반응형
반응형

이전 글 배포자동화(CI/CD) - Github Action/Nuxtjs/Docker/EC2에서는 Github Action을 활용한 배포자동화를 중점적으로 다루었습니다.

 

아래는 이 글의 동영상 강의입니다.

https://youtu.be/eyFO57ZkJaI

 

이걸 조금 더 발전시켜 컨테이너를 2중화 시키고 순차적으로 배포를 해서, 시스템의 중단 없이 배포하는 방법에 대해 알아봅니다.

구성도는 다음과 같습니다.

환경은 이전과 동일합니다.

다만 분산처리를 위해 nginx proxy만 추가 되었습니다.

그리고 docker instance를 2개를 생성합니다.

환경

  • 프론트 : Vuejs (Nuxt)
  • 형상관리 : Git (Github)
  • 빌드 : Docker (Github Action)
  • 서버 : Linux (AWS EC2 micro)
  • 프록시 : nginx

이전 글에서 이미 Docker Image등의 구성이 완료되었으므로, 프로젝트 폴더의 .github/workflow/main.yml 파일을 수정하여 2중화를 구성할 수 있습니다.

 

.github/workflows/main.yml

name: CI/CD Docker

# 트리거를 수행할 브랜치를 지정합니다.
on:
  push:
    branches: [ main ]

# 환경설정
env:
  DOCKER_IMAGE: ghcr.io/${{ github.actor }}/nuxt-auto-deploy
  VERSION: ${{ github.sha }}
  CONTANIER_NAME1: nuxt-auto-deploy1
  CONTANIER_NAME2: nuxt-auto-deploy2
  DOMAIN_NAME: domain or ip
  NAME: prod

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      # github repository에서 checkout
      - uses: actions/checkout@v2
      # docker build 수행
      - name: Set up docker buildx
        id: buildx
        uses: docker/setup-buildx-action@v1
      - name: Cache docker layers
        uses: actions/cache@v2
        with:
          path: /tmp/.buildx-cache
          key: ${{ runner.os }}-buildx-${{ env.VERSION }}
          restore-keys: |
            ${{ runner.os }}-buildx-
      # GitHub 컨테이너 레지스트리에 로그인 후 빌드 & 푸시
      - name: Login to ghcr
        uses: docker/login-action@v1
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - name: Build and push
        id: docker_build
        uses: docker/build-push-action@v2
        with:
          builder: ${{ steps.buildx.outputs.name }}
          push: true
          tags: ${{ env.DOCKER_IMAGE }}:${{ env.VERSION }}
  # 배포 Job
  deploy:
    needs: build  # build 후에 실행되도록 정의
    name: Deploy
    runs-on: [ self-hosted, label-go ] # AWS ./configure에서 사용할 label명
    steps:
      - name: Login to ghcr
        uses: docker/login-action@v1
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - name: Docker run
        run: |
          docker ps -q --filter "name=${{ env.CONTANIER_NAME1 }}" | grep -q . && docker stop ${{ env.CONTANIER_NAME1 }} && docker rm -fv ${{ env.CONTANIER_NAME1 }}
          docker run -d \
                -e VIRTUAL_HOST=${{ env.DOMAIN_NAME }} \
                -e CONTANIER_NAME=${{ env.CONTANIER_NAME1 }} \
                --name ${{ env.CONTANIER_NAME1 }} \
                --restart always ${{ env.DOCKER_IMAGE }}:${{ env.VERSION }}
          docker ps -q --filter "name=${{ env.CONTANIER_NAME2 }}" | grep -q . && docker stop ${{ env.CONTANIER_NAME2 }} && docker rm -fv ${{ env.CONTANIER_NAME2 }}
          docker run -d \
                -e VIRTUAL_HOST=${{ env.DOMAIN_NAME }} \
                -e CONTANIER_NAME=${{ env.CONTANIER_NAME2 }} \
                --name ${{ env.CONTANIER_NAME2 }} \
                --restart always ${{ env.DOCKER_IMAGE }}:${{ env.VERSION }}
          docker image prune -af

env: 아래에 컨테이너 명을 다음과 같이 추가합니다.

  CONTANIER_NAME1: nuxt-auto-deploy1
  CONTANIER_NAME2: nuxt-auto-deploy2
  DOMAIN_NAME: domain or ip

deploy -> steps -> -name: Docker run

아래에 컨테이너 실행 명령을 다음과 같이 입력합니다.

- name: Docker run
run: |
  docker ps -q --filter "name=${{ env.CONTANIER_NAME1 }}" | grep -q . && docker stop ${{ env.CONTANIER_NAME1 }} && docker rm -fv ${{ env.CONTANIER_NAME1 }}
  docker run -d \
        -e VIRTUAL_HOST=${{ env.DOMAIN_NAME }} \
        -e CONTANIER_NAME=${{ env.CONTANIER_NAME1 }} \
        --name ${{ env.CONTANIER_NAME1 }} \
        --restart always ${{ env.DOCKER_IMAGE }}:${{ env.VERSION }}
  docker ps -q --filter "name=${{ env.CONTANIER_NAME2 }}" | grep -q . && docker stop ${{ env.CONTANIER_NAME2 }} && docker rm -fv ${{ env.CONTANIER_NAME2 }}
  docker run -d \
        -e VIRTUAL_HOST=${{ env.DOMAIN_NAME }} \
        -e CONTANIER_NAME=${{ env.CONTANIER_NAME2 }} \
        --name ${{ env.CONTANIER_NAME2 }} \
        --restart always ${{ env.DOCKER_IMAGE }}:${{ env.VERSION }}
  docker image prune -af

이렇게 하면 컨테이너가 순차적으로 2개 구동이 됩니다.

 

배포시에 1개 서버 배포가 완료되어야 다음 단계를 진행하게 되므로, 사용자는 중단 없이 서비스를 이용할 수 있습니다.

 

이제 서버를 분배할 nginx proxy를 설정합니다. 

우리는 jwilder/nginx-proxy 도커 이미지를 사용합니다.

https://hub.docker.com/r/jwilder/nginx-proxy

 

Docker Hub

 

hub.docker.com

EC2에 로그인한 후 vhost.d 폴더를 생성합니다.

/home/ec2-user/vhost.d

 

vhost.d 폴더로 이동한 후,

ec2의 domain명으로 파일을 생성하고 아래 내용을 작성합니다.

- 이 옵션은 nginx의 보안을 위해 버전을 표시하지 않게 합니다.

server_tokens off;

 

docker를 실행합니다.

docker run -d -p 80:80 -p 443:443 
 -v /home/ec2-user/vhost.d:/etc/nginx/vhost.d:ro 
 -v /var/run/docker.sock:/tmp/docker.sock:ro 
 jwilder/nginx-proxy:alpine

 

반응형
반응형

여러 테이블의 데이터를 한꺼번에 처리할 경우가 있습니다.

예를 들면 회원 탈퇴의 경우,

고객의 계정 정보와 다른 여러 테이블에 들어있는 정보들을 한꺼번에 삭제해줘야만 하죠.

이때 특정 데이터가 삭제되지 않고 남게 되면 문제가 발생할 수 있습니다.

이렇게 모든 데이터를 한꺼번에 지우고, 만약 하나라도 오류가 발생할 경우 모든 것을 원복하는 것을 트랜젝션이라 합니다.

 

Nestjs에서 typeorm을 사용할때 트랜젝션 처리 하는 샘플코드를 만들어봅니다.

 

총 3개의 테이블에 데이터가 들어 있습니다.

- user : 사용자

- user_authority : 사용자 권한

- survey : 설문 정보

 

각각의 테이블 정보를 삭제하는 코드는 다음과 같습니다.

- user(사용자) 삭제

async deleteUser(user: User): Promise<any>{
    return await this.userRepository.createQueryBuilder()
        .delete()
        .from(User, 'user')
        .where('id = :id', { id: user.id })
        .execute();
}

- user_authority(사용자 권한) 삭제

async deleteUserAuthorities(user: User): Promise<any>{
    return await this.userAuthorityRepository.createQueryBuilder()
        .delete()
        .from(UserAuthority, 'userAuthority')
        .where('userId = :userId', { userId: user.id })
        .execute();
}

- survey(설문 정보) 삭제

async deleteAllUserSurvey(user: User): Promise<any>{
    return await this.surveyRepository.createQueryBuilder()
        .delete()
        .from(Survey, 'survey')
        .where('userId = :userId', { userId: user.id})
        .execute();
}

마지막에는 commit을 해줍니다.

await queryRunner.commitTransaction()

이 3가지를 transaction으로 처리하는 코드는 다음과 같습니다.

import {DataSource, FindOneOptions, Repository} from 'typeorm';
...

// 회원 탈퇴
async cancelUser(user: User): Promise<any>{
    // transaction 처리
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();
    try{
        // survey 삭제
        await this.deleteAllUserSurvey(user);
        // 사용자 삭제
        await this.deleteUser(user);
        // 사용자 권한 삭제
        await this.deleteUserAuthorities(user);
        // commit
        await queryRunner.commitTransaction()
    } catch (err) {
    	// 실패시 rollback
        await queryRunner.rollbackTransaction();
    } finally {
    	// release
        await queryRunner.release();
    }
}

이렇게 작성하시면 3개가 모두 성공해야만 회원 탈퇴가 성공하게 되고, 하나라도 실패할 경우 Rollback이 됩니다.

이상으로 Nestjs에서 typeorm의 tranaction 처리에 대해 알아보았습니다.

반응형
반응형

이 글은 아래 동영상 강의로 제공됩니다.

 

이번엔 Nestjs로 백엔드 개발을 진행합니다.

 

전체적인 진행 순서는 다음과 같습니다.

  1. kakao developer에서 애플리케이션 생성
  2. 전체 Workflow 이해하기
  3. Nuxtjs(Frontend) 개발
  4. Nestjs(Backend) 개발

 

아래 명령으로 프로젝트를 생성합니다.

nest new kakao-login-back

- package manager : yarn

 

axios package를 추가합니다.

yarn add axios

server port를 3001로 바꿔줍니다.

src/main.ts

await app.listen(3001);

 

src/app.controller에 login api를 만듭니다.

@Post('/login')
  async login(@Body() body: any, @Response() res): Promise<any> {
    try {
      // 카카오 토큰 조회 후 계정 정보 가져오기
      const { code, domain } = body;
      if (!code || !domain) {
        throw new BadRequestException('카카오 정보가 없습니다.');
      }
      const kakao = await this.appService.kakaoLogin({ code, domain });

      console.log(`kakaoUserInfo : ${JSON.stringify(kakao)}`);
      if (!kakao.id) {
        throw new BadRequestException('카카오 정보가 없습니다.');
      }

      res.send({
        user: kakao,
        message: 'success',
      });
    } catch (e) {
      console.log(e);
      throw new UnauthorizedException();
    }
  }

src/app.service.ts에 다음 내용을 추가합니다.

async kakaoLogin(options: { code: string; domain: string }): Promise<any> {
    const { code, domain } = options;
    const kakaoKey = '87073966cb41...';
    const kakaoTokenUrl = 'https://kauth.kakao.com/oauth/token';
    const kakaoUserInfoUrl = 'https://kapi.kakao.com/v2/user/me';
    const body = {
      grant_type: 'authorization_code',
      client_id: kakaoKey,
      redirect_uri: `${domain}/kakao-callback`,
      code,
    };
    const headers = {
      'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
    };
    try {
      const response = await axios({
        method: 'POST',
        url: kakaoTokenUrl,
        timeout: 30000,
        headers,
        data: qs.stringify(body),
      });
      if (response.status === 200) {
        console.log(`kakaoToken : ${JSON.stringify(response.data)}`);
        // Token 을 가져왔을 경우 사용자 정보 조회
        const headerUserInfo = {
          'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
          Authorization: 'Bearer ' + response.data.access_token,
        };
        console.log(`url : ${kakaoTokenUrl}`);
        console.log(`headers : ${JSON.stringify(headerUserInfo)}`);
        const responseUserInfo = await axios({
          method: 'GET',
          url: kakaoUserInfoUrl,
          timeout: 30000,
          headers: headerUserInfo,
        });
        console.log(`responseUserInfo.status : ${responseUserInfo.status}`);
        if (responseUserInfo.status === 200) {
          console.log(
            `kakaoUserInfo : ${JSON.stringify(responseUserInfo.data)}`,
          );
          return responseUserInfo.data;
        } else {
          throw new UnauthorizedException();
        }
      } else {
        throw new UnauthorizedException();
      }
    } catch (error) {
      console.log(error);
      throw new UnauthorizedException();
    }
  }

서버를 실행합니다.

yarn start:dev

브라우저의 콘솔 로그에 사용자 정보가 리턴된것을 확인할 수 있습니다.

이상으로 카카오로그인을 RestAPI를 이용하여 처리하는 방법에 대해 알아보았습니다.

반응형
반응형

이 글은 아래 동영상 강의로 제공됩니다.

 

Frontend 개발은 Nuxtjs를 이용하여 진행하도록 합니다.

 

전체적인 진행 순서는 다음과 같습니다.

  1. kakao developer에서 애플리케이션 생성
  2. 전체 Workflow 이해하기
  3. Nuxtjs(Frontend) 개발
  4. Nestjs(Backend) 개발

 

우선 아래 명령으로 Nuxt 프로젝트를 생성합니다.

npx create-nuxt-app kakao-login-front

- 프로젝트 명 : kakao-login-front

- programing language : Javascript

- Package manager : Yarn

- UI framework : None

- Nuxt.js modules : Axios

- Linting tools : ESLint

- Testing framework : None

- Rendering mode : Single Page App

- Server : Node.js

- Development tools : Enter

- Continuous integration : None

- Version control system : None

 

프로젝트 생성이 완료되면 아래와 같은 메시지가 나옵니다.

에디터에서 프로젝트를 열고, yarn dev를 사용해서 프로젝트를 실행합니다.

브라우저에서 http://localhost:3000번을 입력합니다.

이때 아래와 같은 페이지가 나오면 프로젝트가 정상적으로 만들어진 것입니다.

 

카카오 로그인 기능을 만들기 위해 아래와 같은 버튼이미지가 필요합니다.

아래 사이트에서 다운로드 하실 수 있습니다.

https://developers.kakao.com/tool/resource/login

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

이미지를 static 폴더 아래에 copy합니다.

 

카카오로그인을 사용하기 위해서 kakao.js 파일이 필요합니다.
nuxt.config.js의 'head' 아래에 다음 코드를 추가합니다.

script: [
  {
    src: 'https://developers.kakao.com/sdk/js/kakao.js'
  }
]

 

pages/index.vue 파일에 카카오 로그인 버튼을 추가하고 로그인 method를 작성 합니다.

<template>
  <a @click="loginWithKakao">
    <img src="/kakao_login_large_narrow.png"/>
  </a>
</template>

<script>
export default {
  name: 'IndexPage',
  methods: {
    kakaoInit () {
      Kakao.init('329a6a74...')// KaKao client key
      Kakao.isInitialized()
    },
    async loginWithKakao () {
      await Kakao.Auth.authorize({
        redirectUri: `${window.location.origin}/kakao-callback`
      })
    }
  },
  mounted () {
    this.kakaoInit()
  }
}
</script>

다음과 같이 컴파일 오류가 발생할 수 있습니다.

이 경우 .eslintrc.js 파일을 열고 아래 내용을 추가하면 오류를 해결 할 수 있습니다.

'Kakao' 변수가 선언되지 않았다는 오류이고, 선언되지 않은 변수를 eslint에서 인식할 수 있도록 해 준것입니다.

  globals: {
    Kakao: true
  }

카카오 인증 후 callback 페이지를 아래와 같이 만듭니다.

axios를 이용해 서버API를 호출할 것이기 때문에 nuxt.config.js 다음을 추가합니다.

- baseURL은 서버의 주소를 지정합니다.

  modules: [
    '@nuxtjs/axios'
  ],

  axios: {
    baseURL: 'http://localhost:3001/'
  },

 

pages/kakao-callback.vue

<template>
  <div>
    로그인 중 입니다...
  </div>
</template>

<script>
export default {
  async mounted () {
    try {
      // code 유무 체크
      if (!this.$route.query.code) {
        return this.$router.push('/')
      }
      console.log(`code : ${this.$route.query.code}`)

      // 카카오 로그인 요청
      const body = {
        code: this.$route.query.code,
        domain: window.location.origin
      }
      const response = await this.$axios.$post(
        '/login', body, {}
      )
      console.log(response)
    } catch (error) {
      console.log(error)
    }
  }
}
</script>

브라우저에서 확인을 해봅니다.

확인하고 계속하기를 클릭하면 아래와 같은 화면이 보입니다.

브라우저의 콘솔을 확인해보면 다음과 같이 code 값이 넘어온것을 확인 할 수 있습니다.

이렇게 해서 frontend 작업이 완료되었습니다.

다음시간은 backend 작업을 진행해보겠습니다.

반응형
반응형

이 글은 아래 동영상 강의로 제공됩니다.

 

카카오 로그인(REST API)을 활용하여 웹애플리케이션에서 로그인 기능을 구현하는 것을 배워보도록 하겠습니다.

 

전체적인 진행 순서는 다음과 같습니다.

  1. kakao developer에서 애플리케이션 생성
  2. 전체 Workflow 이해하기
  3. Nuxtjs(Frontend) 개발
  4. Nestjs(Backend) 개발

이번시간은 REST API를 이용한 카카오로그인 전체 Workflow에 대해 설명드립니다. 

1. 서비스 화면에서 카카오로그인 버튼을 클릭합니다. 이때 카카오에서 제공하는 동의 화면이 아래와 같이 나타납니다.

2. 동의를 클릭하면 카카오 인증서버에서 인가코드를 발급해서 우리가 등록한 redirect URI로 전달을 합니다.

 

3. frontend에서 backend로 로그인을 요청합니다.
    URI는 "/auth/login"이고 post로 요청합니다.
    이때 "인가코드"를 파라메터로 전달합니다.

 

4. backend에서 카카오인증 서버로 토큰 발급을 요청합니다.

https://kauth.kakao.com/oauth/token


    이때 인가코드, redirect uri, 애플리케이션Key 등을 파라메터로 전달합니다.

 

5. 정보가 일치할 경우 카카오에서 토큰을 발급하여 backend로 return합니다.

 

6. backend에서 카카오API 서버로 "사용자정보"를 요청합니다.

https://kapi.kakao.com/v2/user/me

7. 사용자 DB에서 해당 사용자를 확인하고 인증 토큰을 발급합니다.

   이때 신규 사용자일 경우 회원가입 처리를 진행한 후 인증 토큰을 발급합니다.

 

8. frontend에서 전달받은 토큰으로 backend로 사용자 정보를 요청합니다.

9. backend에서 토큰을 받아 사용자 정보를 return합니다.

10. frontend에서 사용자 정보 중 이름이 없을 경우 이름을 입력받습니다.

11. frontend에서 입력받은 이름으로 사용자 정보를 update 요청합니다.

12. backend에서 사용자 정보를 update 한 후 변경된 정보를 return 합니다.

 

이상이 전체 로그인을 처리하는 flow입니다.

반응형
반응형

이 글은 아래 동영상 강의로 제공됩니다.

카카오 로그인을 사용하려면 kakao developer 사이트에서 애플리케이션을 만들어야합니다.

이번 글에서는 Kakao Login의 개념과 애플리케이션을 생성하는 법을 알아보도록 하겠습니다.

 

전체적인 진행 순서는 다음과 같습니다.

  1. kakao developer에서 애플리케이션 생성
  2. 전체 Workflow 이해하기
  3. Nuxtjs(Frontend) 개발
  4. Nestjs(Backend) 개발

오늘은 첫번째 순서로 kakao develper에서 애플리케이션을 생성하는 방법에 대한 내용입니다.
그 전에 카카오 로그인이 어떻게 처리되는지도 간략하게 설명합니다.

  1. Kakao Login 이해하기
  2. Kakao Login용 애플리케이션 생성

1. Kakao Login 이해하기

카카오 로그인을 이용하면 사용자가 별도의 정보를 입력하지 않고도 손쉽게 로그인을 할 수 있습니다.

간편하게 로그인을 할 수 있으므로 요즘 많은 서비스에서 카카오로그인을 이용하여 로그인 처리를 하고 있습니다.

 

Kakao developers에서 자세한 문서를 제공하고 있으므로 아래 페이지를 방문하여 내용을 읽어보도록 합니다.

https://developers.kakao.com/docs/latest/ko/kakaologin/common

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

카카오로그인 Step을 요약하면 다음과 같습니다.

  1. 카카오로그인 버튼을 클릭합니다.
  2. 카카오 동의 화면에서 동의를 합니다. 이때 카카오 인가코드가 발급됩니다.
  3. RedirectURI로 인가코드가 전달됩니다.
  4. 인가코드로 카카오 인증토큰을 요청합니다.
  5. 발급받은 인증토큰으로 카카오 사용자 정보를 요청합니다.
  6. 사용자 정보를 확인하여 신규회원일 경우 회원 가입을 처리합니다.
  7. 기존 회원일 경우 서버에서 로그인 세션 또는 토큰을 발급합니다.

카카오 로그인은 모바일, 웹, 서버등 다양한 플랫폼에서 처리가 가능합니다. 우리는 Backend와 Frontend를 분리하여 처리하므로 로그인을 위해서는 Backend Server에서 토큰을 발급하여 로그인을 체크하도록 합니다. 그러기 위해서는 Frontend에서 로그인 인가코드를 받아 서버로 로그인 요청시 인가코드를 전송하고, 서버에서 인가코드를 받아 카카오토큰을 발급받고, 카카오 사용자 정보를 조회하는 순서로 처리를 합니다. 이 단계가 완료되면 서버에서 토큰을 발급해 사용자의 로그인을 처리합니다.

 

2. 애플리케이션 생성(in Kakao Developers)

카카오 로그인을 사용하기 위해서는 Kakao Developers 사이트에서 애플리케이션을 생성하여 키를 발급받아야 합니다.

자세한 안내는 아래 url을 참고하세요.

https://developers.kakao.com/docs/latest/ko/getting-started/app

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

애플리케이션 생성을 간단히 요약하면 다음과 같습니다.

1. kakao developers 사이트에 로그인합니다.

2. 상단의 내애플리케이션 메뉴를 클릭하고 애플리케이션 추가하기 버튼을 클릭합니다.

3. 앱 이름과 사업자명을 입력하고 저장 버튼을 클릭합니다.
    저는 nestSocialLogin라는 이름으로 생성을 했습니다.

4. 아래와 같이 앱이 만들어졌습니다.

5. 앱을 클릭하고 들어가면 다음과 같이 앱키를 확인하실 수 있습니다.

6. 앱을 사용하기 위해서는 하단의 플랫폼 설정하기를 해주어야 합니다.

7. 우리는 web을 개발할 것이므로 web 플랫폼 등록을 선택합니다.
   사이트 도메인은 최대 10개까지 등록이 가능합니다.
   우선은 로컬에서만 개발을 진행하므로 "http://localhost:3000"을 등록합니다.(3000은 포트입니다.)

8. 아래와 같이 도메인이 등록되면, Redirect URI를 등록해 주시면 됩니다.
   Redirect URI는 카카오 로그인화면에서 호출될 우리가 만든 서비스 URI입니다.

9. 우선 로그인 기능을 사용하기 위해 "활성화 설정"을 ON으로 변경합니다. 그리고 하단의 "Redirect URI 등록" 버튼을 클릭합니다. 

10. Redirection 될 URI 를 입력하고 저장합니다.

11. 카카오로그인 -> 동의항목 설정을 해줍니다.

    좌측의 카카오로그인 메뉴 아래 동의항목을 클릭합니다.

   로그인시에 카카오에서 가져올 정보를 설정을 통해 "필수 동의" 또는 "선택 동의"로 설정합니다.

 

이렇게 하면 카카오 로그인을 개발하기 위한 설정은 완료되었습니다.

 

실제 로그인 프로그램을 만드는 것은 다음 글을 참고 해주세요.

반응형
반응형

Nuxtjs에서 날짜를 그냥 뿌려주면 다음과 같은 형식으로 나타나게 됩니다.

2022-05-13T22:55:12.000Z

이것을 다음과 같은 형식으로 보여주는 방법에 대해 알아보겠습니다.

2022/05/14


순서는 다음과 같습니다.

  • nuxt.config.js에 필터 추가
  • plugin 폴더에 filter.js 파일 생성
  • vue에서 필터 사용

 

nuxt.config.js에 필터 추가


nuxt.config.js 파일에서 plugins: [] 에 다음 코드를 추가합니다.

plugins: [
   '~/plugins/filter.js',
],

 

plugin 폴더에 filter.js 파일 생성


plugin 폴더에 filter.js 파일을 생성하고 다음 코드를 입력하고 저장합니다.

import Vue from 'vue';
import moment from 'moment';

Vue.filter('formatDate', (value) => {
    return moment(String(value)).format('YYYY/MM/DD');
})

 

vue에서 필터 사용


.vue 파일에서 다음과 같이 입력합니다.

{{createdAt | formatDate}}

createdAt 이라는 필드의 값을 formatDate라는 필터를 적용하라는 뜻입니다.
이렇게 하면 다음과 같은 결과가 나오는 걸 확인 할 수 있습니다.

2022/05/14
반응형

+ Recent posts