반응형

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

https://youtu.be/9ILkDtTB5j0

 

개발자에 큰 힘을 줄 수 있는 4가지 기술에 대해 소개 합니다.

  • Git
  • Linux
  • Docker
  • Cloud Computing

Git

Git은 오픈소스 버전 관리 시스템입니다.

버전 관리 시스템은 여러대의 컴퓨터에서 소스를 개발하거나, 여러명이 함께 개발을 할때 반드시 필요한 소프트웨어입니다.

Git 이전에는 CVS, SVN등이 있었으나 많은 문제점들로 인해 개발자들이 사용에 어려움을 느끼고 있었습니다. 이를 해결하기 위해 Linus Torvalds가 개발을 하고 2005년에 출시된 서비스입니다.

Git을 좀더 쉽게 사용하도록 하기 위해 Git을 웹으로 구현한 것이 github입니다. 개인적으로 사용할 경우 무료이므로 많은 사람들이 이곳에서 소스를 관리하고 있습니다.

github은 Microsoft가 2018년에 75억 달러에 인수를 하였습니다.  

 

Linux

Linux는 오픈소스 운영체제(Operating System)입니다.

OS는 사용자가 컴퓨터 하드웨어를 사용할 수 있도록 도와주는 역할을 합니다. 하드웨어는 CPU, RAM, 입력장치, 저장장치, 출력장치, 네트워크 장치 등이 있습니다.

Windows OS는 서버로 사용하기에 적당한 시스템은 아닙니다. 그래서 이전에는 많은 기업들이 Unix라는 OS를 사용했었습니다.

그러나 Unix의 경우 고가의 장비와 함께 제공이 되고 있었기에, 개인이나 작은 기업에서는 사용이 어려웠었습니다.

이 Unix를 오픈소스화 하여 개발한 것이 Linux입니다.

Linux도 Linus Torvalds가 개발을 하였고 1991년에 출시를 하였습니다. 요즘 개발자들이 가장 많이 사용하고 있는 시스템을 2가지나 만들어내다니 정말 대단한 사람입니다.

Linux를 모든 개발자가 알아야 하는 것은 아니지만, 서버를 운영한다거나 맥OS를 좀 더 잘 다루기 위해서는 알아두면 굉장히 유익합니다.

Docker

리눅스의 프로세스를 격리하는 기술을 패키징하여 솔루션으로 만든 제품이 Docker입니다.

2014년에 Docker사에서 발표한 서비스입니다.

Docker는 한 개의 서버에 컨테이너 형태로 여러개의 서버를 운용할 수 있습니다.

Text 기반의 Dockerfile, Docker-compose 등을 이용해서 서버를 손쉽게 구축할 수 있습니다.

Docker는 Cloud 서비스와 잘 어우러져서 요즘 굉장히 많이 사용되고 있습니다. 

서버를 효율적으로 관리/운영할 때, 개발 환경을 템플릿화 하여 사용할 때 사용할 수 있습니다.

 

Cloud Computing

전통적으로 서버를 운영하는 방식을 on-premise라고 합니다. 이 경우 서버를 구매하여 설치 및 운영까지 모두 직접 하여야 합니다.

따라서 서버를 운영하는 것은 많은 비용과 자원이 필요한 것이었습니다.

이런 불편함을 없애고자 나온 것이 Cloud Computing입니다. 이 경우 필요한 Computing 자원만을 선택적으로 구매하여 즉시 사용할 수 있게 되어 on-premise의 많은 어려움을 해결 할 수 있게 되었습니다.

 

 

이 4가지는 개발자에게 필수는 아니지만 알게 되면 엄청난 무기가 될 수 있는 기술입니다.

꼭 배우셔서 더 능력있는 개발자로 거듭나시길 바랍니다.

 

반응형
반응형

다음은 이 글의 동영상 강의 링크입니다.
 
요즘은 많은 종류의 프로그래밍 언어들이 있습니다. 개발자가 되려고 할 때 어떤 언어를 선택해야 할지 고민을 많이 하게됩니다. 이럴때 어떻게 선택하면 좋을지와 추천 언어는 어떤것이 있는지 알아보겠습니다.
 
개발자의 종류는 다양하지만, 최근들어 일반적으로 Frontend와 Backend 개발자로 나누고 있습니다.
단어에서 주는 느낌처럼 사용자들이 직접 만나게 되는 부분을 Frontend, 그 뒤의 보이지 않는 부분을  Backend 라고 합니다.
 
그림과 같이 사람이 볼 수 있는 부분이 Frontend, 보이지 않는 부분이 Backend 라고 생각하면 됩니다.

카카오톡에 로그인 하는 예를 들어보면,
  1. 카톡 로그인 창이 보이는 부분이 Frontend입니다.
    여기에서 사용자는 아이디와 패스워드를 입력하고 로그인 버튼을 클릭합니다.
  2. 아이디/패스워드 정보가 Backend로 전달이 되어집니다.
    이것으로 Database를 검색하여 사용자 인증을 처리하고, 정상 사용자일 경우 친구 및 대화 목록을 가져와서 Frontend로 전달을 합니다.
  3. Frontend에서는 Backend에서 온 Data를 이용해서 대화목록 화면을 보여줍니다.

 

정리하면,
Frontend는 사용자에게 보여지는 화면을 주로 처리하는 프로그램을 개발하고,
Backend는 Frontend의 요청에 의해 비즈니스 로직을 처리하고, 데이터를 처리하고 Interface를 처리하는 프로그램을 개발합니다.
 
Frontend의 경우 앱과 웹으로 구분될 수 있습니다.
앱의 경우는 Android와 iOS 개발을 의미합니다.
  • Android는 과거 Java 언어를 사용하였으나 최근엔 Kotlin(코틀린)이라는 언어를 사용합니다.
  • iOS의 경우는 Swift(스위프트)를 사용합니다.
웹의 경우는 자바스크립트 프레임워크를 많이 사용합니다. 현재 많이 쓰이고 있는 것은 다음과 같습니다.
  • React
  • Vue
이 둘의 차이는 다음과 같습니다.
물론 웹의 경우는 html, css도 어느정도 알고 있어야 개발이 가능합니다.
 
Backend의 경우 최근 Java와 NodeJS를 많이 사용합니다.
백엔드의 경우 그 외에 Database는 기본적으로 알고 있어야 합니다.

 

이 외 다른 언어들은
  • Python의 경우는 배우기 쉬운 언어라 많이 사용하고 있습니다.
  • Python은 데이터 분석 영역에서도 많이 사용합니다.
  • Php의 경우는 wordpress라는 브로그 사이트를 만들 수 있는 오픈 소스를 등에 업고 많이 사용되고 있습니다.
  • 시스템적으로 빠른 성능이 필요할 경우는 C나 C++을 사용하는 곳도 있습니다.
 
결론을 말씀 드리면
  • 요즘 개발자로 취업을 하기 좋은 언어를 추천하라고 하면,
  • 당연히 Javascript 기반의 언어입니다. 백엔드와 프론트엔드를 모두 커버할 수 있기 때문이죠.(Full Stack)
  • 먼저 frontend/backend를 결정하시고
  • frontend일 경우는 react, vue 중에서 하나를
  • backend일 경우는 nodejs, java 중에서 하나를 선택하시는 것을 추천드립니다.

반응형
반응형

다음은 이 글의 영상 버전입니다.

https://youtu.be/5SlcbnUpkIw

 

이 글은 개발자의 길을 막 시작하셨거나, 새롭게 가시려는 분들을 위해 작성한 글입니다.

개발자라는 직업을 갖기 전에 어떤 고민들을 해보아야 할지를 이야기 합니다.

 

1. 적성에 맞을까?

직업으로서의 개발자는 평생토록 매일 8시간씩 자리에 앉아 컴퓨터를 들여다 보아야 하는 일입니다. 이렇게 오랜 시간 일을 하려면 이것이 내 적성에 맞는가를 가장 먼저 고려해 보아야 합니다. 자리에 진득하게 앉아 오래도록 코딩을 하더라도 일이 재미있게 느껴져야지만 개발자의 길을 갈 수 있습니다. 몇개월 공부하면서 이 일이 힘들게만 느껴진다면 다시 한번 진지하게 고민을 해보아야 합니다. 저는 오래도록 이 일을 했지만, 개발하는 것이 재미있다고 느껴져서 아직까지도 꾸준히 이 일을 할 수 있는 것 같습니다.

한발 더 나아가 이 일에 대한 애정과 열정이 있을때, 내가 이 일을 더 잘하기 위한 시간을 투자하게 되고, 그럴때 더 일을 잘 할 수 있게 되는 것이죠.


다음은 어떤 책에서 발췌한 글입니다. 어떤 일을 잘 하기 위한 진리라고 할 수 있죠.

 

영화속 해커는 키보드를 몇번 두드리면 마법의 문이 열리는 듯한 일들이 일어나곤 합니다. 하지만 현실속의 개발자는 이것과는 거리가 멀죠.

개발자들이 매일 하는 것은 코딩, 테스트, 코딩, 테스트의 반복입니다. 심지어 개발하고 있는 것이 잘 풀리지 않아, 몇일 동안 골머리를 앓기도 합니다. 하지만 이것을 어떻게든 해내야만 하는게 현실의 개발자입니다. 이런 끈기야 말로 개발자가 갖추어야 할 자질이기도 합니다.

 

개발자는 배움의 끈을 놓을 수 없는 직업입니다. 다시말해 평생을 배우고 또 배워야 합니다. 따라서 수동적인 배움이 아닌 열정을 가지고 배울 수 있어야만 이 일을 더 잘 해 낼 수 있습니다.

 

이런 어려움에도 불구하고 개발자는 매우 가치있고 멋진 일입니다. 무엇보다 일의 성취감이 높고, 많은 사람들과 잘 융합되어 질때 엄청난 시너지를 발휘하며 즐겁게 일할 수 있는 직업입니다. 또 요즘은 개발자들에 대한 처우가 점점 좋아지고 있는 추세입니다. 복지는 물론 연봉도 높은 일자리들이 많이 생기고 있고, 앞으로는 더욱 그럴 것입니다.

 

2. 비전공자도 개발자가 될 수 있나요?

당연합니다. 전공은 그다지 중요하지 않습니다. 

개발자에게 가장 중요한 것은 기술력입니다. 하지만 그것만큼 중요한 것이 커뮤니케이션과 협업 능력입니다. 대부분의 소프트웨어는 누군가의 필요에 의해 만들어지기 때문에, 그 맥락을 정확히 이해하기 위해선 소통이 너무나도 중요합니다. 

한 인터뷰에서 스티브잡스는 이런 말을 했습니다.

"One of the keys to Apple is Apple's an incredibly collaborative company."

"애플의 핵심 요소중 하나는 애플이 놀랍도록 협력적인 회사라는 것이다."

세계 최고의 기술력을 가진 회사 애플에서도 협력을 무엇보다 중요한 가치로 여긴다고 말합니다.

 

개발자는 개발팀에 소속되어서 동료들과 호흡을 맞춰 일합니다. 또 기획자, 디자이너들과도 긴밀하게 협력을 해야지만 제대로 된 품질의 아웃풋을 만들 수 있습니다. 거기에 사용자를 고려하고 마케팅적인 부분도 생각을 해야하기 때문에 많은 팀들과 긴밀한 협력을 유지해야만 합니다.

 

3. 관객이 아닌 플레이어

요즘은 유튜브를 통해 개발을 배우시는 분들이 많습니다. 좋은 컨텐츠도 많고 그 만큼 예전에 비해 개발을 쉽게 접할 수 있게 되었습니다. 하지만 동영상으로 개발을 배울 때 주의해야 할 것이 있습니다. 바로 눈으로 코딩을 하는 것이 아닌, 손으로 코딩을 하도록 해야합니다. 우리가 많은 축구 경기를 봄으로써 게임에 대한 이해도가 높아질 수는 있지만, 실제로 자신이 축구장에 가서 공을 차는 것은 다른 차원의 문제입니다. 따라서 영상을 통해 코딩을 배우더라도 반드시 자신의 손으로 직접 코딩을 해보고, 자신의 부족한 것들을 꾸준히 채워가는 작업을 해야합니다.

 

4. 기술보다는 미션이 중요

배달의 민족은 음식점과 소비자를 연결하는 앱을 만들었습니다. 초기 배달의 민족은 길에서 전단지를 주워 전화를 통해 연결해 주는 것 부터 시작을 했습니다. 그 후에 시스템을 만들어 자동화 시켰습니다. 이것은 어떤 미션을 해결하기 위해 필요한 기술을 구현하는 것이 중요하다는 의미입니다. 단순 개발 기술만으로는 의미있는 변화가 생기지 않습니다.

따라서 우리는 미션을 수행하기 위한 기술들을 고민하고, 연구하여 해결해 나가는 것이 필요합니다.

 

5. 프로젝트를 통해서 배우기

기술적인 것을 배우는 데 그치지 말고, 그것들을 활용해서 할 수 있는 프로젝트를 수행하는 것이 기술을 가장 빨리 배울 수 있는 방법입니다.

프로젝트는 곧 실전이기 때문에 훨씬 더 복잡한 기술적인 문제들에 부딪힐 수 있습니다. 이런 어려움들을 극복하는 것이 실전 감각을 키우는 가장 빠른 방법입니다.

프로젝트는 혼자서 수행할 수도 있고, 많은 인원이 같이 할 수도 있습니다. 혼자가 아닌 프로젝트에서는 협력하는 법도 자연스레 배울 기회를 얻게 됩니다.

 

6. 과정을 행복하게

똑같은 길을 가더라도 주변 사람들과 같이 웃으며 가는 사람이 있고, 먼저 가려고 다툼을 일으키는 사람이 있습니다. 결과가 모든 과정을 무시할 수는 없습니다.

 

에머슨이라는 작가는 "무엇이 성공인가"라는 글을 통해 성공을 다음과 같이 표현 했습니다.

성공은 큰 일을 이뤄내는 것보다,

주변 사람들과 행복하게 지내는것,

자기일에서 만족감을 느낄 수 있는 것,

누군가에게 조금이라도 도움을 주는 삶을 사는 것을 통해 만날 수 있는 것입니다.

 

이런 것들을 고민하고 잘 기억하셔서 여러분의 도전이 꼭 성공하시길 바랍니다.

 

 

반응형
반응형

지난 글에 이어 Github Desktop 사용법에 대해 조금 더 알아보겠습니다.

 

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

https://youtu.be/n77Jtz1iP_M

 

순서

  • Private 프로젝트 만들기
  • Github desktop에서 github.com 계정으로 로그인
  • Branch 개념 이해하기
  • Branch 생성
  • Branch Merge

 

Private 프로젝트 만들기

외부에 공개되지 않는 자신만의 프로젝트를 만들기 위해서는 private으로 프로젝트를 만듭니다.

  • www.Github.com 에서 Repository 메뉴로 이동합니다.
  • 우측 상단의 [New] 버튼을 클릭합니다.

  • [프로젝트명]을 입력합니다.(예: test)
  • [public / private] 항목에서 private를 선택합니다.

  • [Add a README file] 이라고 된 부분을 체크하고, [Create repository] 버튼을 클릭하여 프로젝트를 생성합니다.

  • readme 파일이 하나 추가된 [test repository]가 아래와 같이 생성됩니다.

Github Desktop에서 github.com 로그인 하기

private로 만들어진 프로젝트는 로그인을 해야만 사용이 가능합니다. github desktop에서는 github 로그인 기능을 제공하므로, 이것을 알아보겠습니다.

  • github desktop을 실행합니다.
  • 상단의 [Github Desktop] 메뉴에서 [Preferences]를 클릭합니다.

 

  • [Accounts] 메뉴에 들어가면 Github.com 항목의 [Sign In]을 클릭합니다.

  • Sign in Using Your Browser
    - 현재 github.com에 로그인한 브라우저를 통해서 로그인을 할 수 있습니다.

 

레파지토리 추가하기

  • Repository명 옆의 버튼을 클릭합니다.

  • clone repository를 선택합니다.
  • github.com tab을 클릭한 후 test repository를 선택하고 clone 버튼을 클릭하면 소스가 다운로드 됩니다.

 

Branch 만들기

  • 화면에서 main branch 옆의 화살표를 클릭합니다.

  • New Branch를 선택합니다.

  • 브랜치명을 "develop" 이라고 입력하고 "Create Branch"를 클릭합니다.

  • "Publish branch"를 클릭하여 github.com에 share 합니다.

  • github.com에서 새로고침해보면 branch가 2개가 된것을 확인할 수 있습니다.

 

Branch 개념 이해하기

  • 한개의 Branch만 사용할 경우 (Main Branch)
    • Main Branch에 push될때 운영 배포가 이루어지게 설정을 해 놓았다면,
    • 소스를 push 할때마다 운영서비스에 반영이 됩니다.
    • 소스에 대한 검증이 제대로 안될 경우 장애가 발생할 수 있습니다.

  • 두개의 Branch를 사용할 경우 (Develop Branch)
    • Sub Branch를 활용해서 개발기에 배포를 하고 소스를 검증한 후
    • Main Branch에 Merge 하여 안전하게 운영 서버에 배포를 할 수 있습니다.

Merge 하기

develop branch의 소스를 변경한 후 main에 merge 하는 방법입니다.

  • develop branch를 선택합니다.
  • 소스를 수정합니다. 

  • develop branch에 commit과 push를 합니다.

  • main branch로 변경합니다.

  • 상단 메뉴에서 "Branch"-"Merge Into Current Branch"를 선택합니다.

  • Merge할 브랜치를 선택하는 화면에서 "develop" branch를 선택하고 "Create a merge commit" 버튼을 클릭합니다.

  • "Push origin" 버튼을 클릭하면 Merge가 완료됩니다.

 

 

반응형
반응형

Frontend에서 S3 버킷에 파일을 업로드 하는 것을 알아보겠습니다.

 

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

https://youtu.be/7FsycVjRq8Q

 

slider-front 프로젝트를 열고 admin 페이지를 생성합니다.

내용은 index.vue를 복사하여 만듭니다.

/pages/admin/index.vue

<template>
  <div>
    <div>관리자 페이지</div>
  </div>
</template>
<script>
export default {
  name: 'IndexPage',
  computed: {
    accessToken() {
      return this.$store.state.accessToken
    }
  }
}
</script>

관리자 메뉴 링크 클릭시 위 페이지로 이동하도록 아래와 같이 변경합니다.

/layouts/default.vue

async admin() {
  await this.$router.replace('/admin/');
}

 

관리자 메뉴의 링크가 잘 작동하는지 테스트를 합니다.

 

dotenv와 aws-sdk 패키지를 추가합니다.

yarn add @nuxtjs/dotenv dotenv aws-sdk

aws 설정을 위해 plugins 폴더를 추가하고 env-var.js 파일을 아래와 같이 추가합니다.

export default ({
    app, context
}, inject) => {
    const env = {}
    env.S3_BUCKET = 'codegear-slider-bucket'; //버킷명 입력
    env.S3_REGION = 'ap-northeast-2'; //리전명 입력
    env.S3_IDENTITY_POOL_ID = '설정한 IDENTITY_POOL_ID값 입력';
    inject('env', env)
}

 

파일 업로드를 위해 Bootstrap-Vue의 Form File Component를 추가합니다.

https://bootstrap-vue.org/docs/components/form-file

 

BootstrapVue

Quickly integrate Bootstrap v4 components with Vue.js

bootstrap-vue.org

Admin 페이지를 다음과 같이 수정합니다.

/admin/index.vue

<template>
    <div>
        <b-form-file
            ref="file-input"
            v-model="file1"
            :state="Boolean(file1)"
            placeholder="Choose a file or drop it here..."
            drop-placeholder="Drop file here..."
            accept="image/*"
        ></b-form-file>
        <div class="mt-3">Selected file: {{ file1 ? file1.name : '' }}</div>
        <b-button @click="clearFiles" class="mr-2">Reset</b-button>
        <b-button @click="upload" class="mr-1">Upload</b-button>
    </div>
</template>

<script>
import AWS from 'aws-sdk';

export default {
    name: 'IndexPage',
    data() {
        return {
            file1: null,
            bucketName: this.$env.S3_BUCKET,
            bucketRegion: this.$env.S3_REGION,
            IdentityPoolId: this.$env.S3_IDENTITY_POOL_ID,
        }
    },
    computed: {
        accessToken() {
            return this.$store.state.accessToken;
        }
    },
    methods: {
        clearFiles() {
            this.$refs['file-input'].reset()
        },
        async upload() {
            if(!this.file1) {
                alert('File을 선택해주세요.')
            }else{
                console.log(this.file1);
                console.log(`${this.bucketRegion} ${this.bucketName}`);
                AWS.config.region = this.bucketRegion;
                AWS.config.credentials = new AWS.CognitoIdentityCredentials({
                    IdentityPoolId: this.IdentityPoolId,
                });
                const s3 = new AWS.S3({
                    apiVersion: '2006-03-01',
                    params: {
                        Bucket: this.bucketName+'/images'
                    }
                });
                await s3.upload({
                    ACL: 'public-read',
                    Body: this.file1,
                    Key: this.file1.name
                }, (error)=>{
                    if(error){
                        this.errorHandler(error);
                        // return alert('There was an error uploading your photo: ', error.message);
                    }
                }).promise().then((data)=>{
                    console.log('File uploaded!!!')
                    console.log(data);
                })
            };
        },
    }
}
</script>

파일 업로드 테스트를 해봅니다.

위와 같이 정상적으로 업로드가 안되고 AccessDenied가 나올 경우,
AWS의 IAM - 역할 메뉴에서 다음 항목을 검색합니다.

Cognito_SliderS3AccessUnauth_Role

해당항목을 클릭하고 들어가면,
아래와 같은 정책 이름이 보입니다.

"oneClick_Cognito_SliderS3AccessUnauth_Role_..." 항목을 클릭합니다.

JSON을 선택하여 아래와 같이 작성 후 정책 검토를 한 후 저장합니다.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:*"
            ],
            "Resource": [
                "arn:aws:s3:::codegear-slider-bucket/*",
                "arn:aws:s3:::codegear-slider-bucket"
            ]
        }
    ]
}

 

 

반응형
반응형

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

https://youtu.be/A8FcYGEe2i4

이번 시간은 아마존에서 제공하는 Storage Service인 S3에 파일을 업로드 하는 것을 알아봅니다.

S3는 Simple Storage Service의 각 단어 첫번째 글자가 S가 3개라는 의미입니다.

S3를 이용하면 이미지 파일을 저장할 수 있고, 저장된 이미지를 웹에서 볼 수 있습니다.

 

순서는 다음과 같습니다.

  • AWS S3에 버킷 생성
  • Cognito Identity Pool(자격 증명 풀) 생성
  • IAM에서 자격 증명 풀에 S3 권한 추가

AWS에서 S3 버킷 생성 

우선 AWS에 로그인 한 후 "S3"를 검색하여 서비스로 이동합니다.

AWS S3

 

S3를 사용하기 위해서는 아래와 같이 Bucket을 생성해 주어야 합니다.

  • 왼쪽 메뉴의 "버킷"을 클릭
  • "버킷만들기" 버튼을 클릭버킷의 이름은 S3 서비스를 통틀어 유일해야만 함.

  • 리전을 선택한 후
  • 버킷 선택을 클릭

  • 퍼블릭 액세스 차단 설정에서 "모든 퍼블릭 엑세스 차단"의 체크 박스를 해제.
    • 현재는 샘플 프로젝트이므로 보안 작업 없이 진행합니다.
    • 운영 환경에서는 권한을 반드시 설정하여 사용하시기 바랍니다.

  • "모든 퍼블릭 액세스 차단을 비활성화하면..." 아래의 체크박스를 체크.

  • "버킷 만들기" 클릭

  • 버킷 생성이 완료되면 생성된 버킷명을 클릭하고, "권한" 탭을 클릭

 

  • CORS 항목에서 "편집"을 클릭한 후 다음 내용을 입력합니다.
[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "GET",
            "PUT",
            "POST",
            "HEAD"
        ],
        "AllowedOrigins": [
            "*"
        ],
        "ExposeHeaders": [
            "x-amz-server-side-encryption",
            "x-amz-request-id",
            "x-amz-id-2"
        ],
        "MaxAgeSeconds": 3000
    }
]

Cognito Identity Pool(자격 증명 풀) 생성

  • aws에서 cognito 서비스를 검색하여 이동합니다.

  • "자격 증명 풀 관리"를 클릭.

  • "새 자격 증명 풀 만들기"를 클릭.

  • 자격 증명 풀 이름 입력(예: SliderS3Access)
  • "인증되지 않은 자격 증명에 대한 액세스 활성화" 클릭

  • "풀 생성" 버튼 클릭

  • "허용" 버튼 클릭

  • 샘플 코드의 플랫폼에서 "JavaScript"를 선택하면 아래와 같은 코드가 나타납니다.

  • 이 코드를 소스에 추가하면 업로드가 가능해집니다.

IAM에서 권한 추가

  • AWS의 IAM 서비스로 이동합니다.

  • "역할" 메뉴에서 "slider"로 검색.
  • 생성된 Role을 클릭.(예 : Cognito_SliderS3AccessAuth_Role)

  • "권한 추가" 클릭 후 "정책 연결"을 선택.

  • 기타 권한 정책에서 "s3"로 검색 후 "AmazonS3FullAccess"를 선택.
  • "정책 연결" 버튼을 클릭.

이렇게 하면 S3에 업로드 할 수 있는 권한 생성 및 설정이 완료되었습니다.

반응형
반응형

이번 시간은 front에서 jwt 토큰을 추가하여 사용자 조회를 하고, 권한 관리를 하는 기능을 구현 해 봅니다.

백엔드(slider-api)

토큰 Validation

권한 관리를 위해 JWT Token validation을 추가 합니다.

이것은 사용자가 header에 token을 보냈을때 사용자 정보를 조회하는 기능입니다.

/src/auth/security/passport.jwt.strategy.ts

async validate(payload: Payload, done: VerifiedCallback): Promise<any> {
    const user = await this.authService.tokenValidateUser(payload);
    if(!user) {
        return done(new UnauthorizedException({message: 'user does not exist'}), false);
    }
    return done(null, user);
}

authService에 tokenValidateUser를 추가합니다.

/src/auth/auth.service.ts

async tokenValidateUser(payload: Payload): Promise<User| undefined> {
    const userFind = await this.userService.findByFields({
        where: { id: payload.id }
    });
    this.flatAuthorities(userFind);
    return userFind;
}

private flatAuthorities(user: any): User {
    if (user && user.authorities) {
        const authorities: string[] = [];
        user.authorities.forEach(authority => authorities.push(authority.authorityName));
        user.authorities = authorities;
        for(const auth of authorities){
            if(auth === RoleType.ADMIN){
                user.isAdmin = true;
	        }
        }
    }
    return user;
}

로그인한 사용자만 접근할 수 있도록 Auth Guard를 만듭니다.

/src/auth/security/auth.guard.ts

import { ExecutionContext, Injectable, UnauthorizedException } from "@nestjs/common";
import { AuthGuard as NestAuthGuard } from "@nestjs/passport";
import { Observable } from "rxjs";

@Injectable()
export class AuthGuard extends NestAuthGuard('jwt'){
    canActivate(context: ExecutionContext): boolean | Promise<boolean> | Observable<boolean> {
        return super.canActivate(context)
    }

    handleRequest(err, user, info) {
        if (err || !user) {
            throw err || new UnauthorizedException();
        }
        return user;
    }
}

권한별로 접근할 수 있도록 Role Guard를 만듭니다.

여기서는 일반 사용자와 관리자 권한을 체크하려고 합니다.

/src/auth/security/role.guard.ts

import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { User } from '../../domain/user.entity';


@Injectable()
export class RolesGuard implements CanActivate {
    constructor(private readonly reflector: Reflector) {}

    canActivate(context: ExecutionContext): boolean {
        const roles = this.reflector.get<string[]>('roles', context.getHandler());

        if (!roles) {
            return true;
        }

        const request = context.switchToHttp().getRequest();
        const user = request.user as User;
        console.log(`auth include : ${user.authorities.some(role => roles.includes(role))}`)

        return user && user.authorities && user.authorities.some(role => roles.includes(role));
    }
}

AuthController에서 사용자 정보를 조회하는 API를 추가합니다.

이 api는 "/auth/user"를 통해 호출할 수 있으며,

@UseGuards(AuthGuard)를 사용하였으므로 로그인한 사용자만 사용이 가능합니다.

/src/auth/auth.controller.ts

// 사용자 정보 조회
@UseGuards(AuthGuard)
@Get('/user')
getUser(@Request() req): any {
    console.log(req);
    return req.user;
}

 

프론트엔드(slider-front)

사용자 정보 조회

이제 front에서 로그인 후 사용자 정보를 조회하는 로직을 추가합니다.

 

우선 store에 user와 isAdmin을 추가합니다.

/store/index.js

export const state = () => ({
    accessToken: '',
    user: '',
});

export const mutations = {
    accessToken (state, data) {
        state.accessToken = data;
    },
    user (state, data) {
        state.user = data;
    },
}

로그인 후 api를 호출해 사용자 정보를 조회하고 store에 저장합니다.

/pages/kakao-callback.vue

const response = await this.$axios.$post(
    '/auth/login', body, {}
)
if(response){
  const accessToken = response.accessToken;
  console.log(accessToken);
  // 토큰을 스토어에 저장하기
  this.$store.commit('accessToken', accessToken);
  const options = {
    headers: {
      Authorization: `Bearer ${accessToken}`
    },
  };
  //토큰을 이용하여 사용자 정보 조회하기
  const user = await this.$axios.get("/auth/user", options);
  const loginUser = user.data;
  console.log(loginUser);
  this.$store.commit('user', loginUser);
}
return this.$router.push('/')

Navigation에서 관리자일 경우만 관리자 링크를 보여주도록 추가합니다.

/layouts/default.vue

<template>
  <div>
    <b-navbar toggleable="lg" type="dark" variant="info">
      <b-navbar-brand href="#">Slider</b-navbar-brand>

      <b-navbar-toggle target="nav-collapse"></b-navbar-toggle>

      <b-collapse id="nav-collapse" is-nav>
        <b-navbar-nav class="ml-auto" v-if="!accessToken">
          <b-nav-item href="/login" right>로그인</b-nav-item>
        </b-navbar-nav>
        <b-navbar-nav class="ml-auto" v-if="accessToken && accessToken!==''">
          <b-nav-item @click="admin" right v-if="user.isAdmin">관리자</b-nav-item>
          <b-nav-item @click="logout" right>로그아웃</b-nav-item>
        </b-navbar-nav>
      </b-collapse>
    </b-navbar>
    <nuxt/>
  </div>
</template>
<script>
export default {
  name: 'Layout',
  data() {
    return {
      auth: false
    }
  },
  mounted() {
    this.$nuxt.$on('auth', auth=>{
      this.auth = auth
      console.log(auth)
    })
  },
  methods: {
    async logout() {
      await this.$store.commit('accessToken', '');
      await this.$router.push('/');
    },
    async admin() {
      alert('관리자 메뉴!!!')
    }
  },
  computed: {
    accessToken() {
      return this.$store.state.accessToken
    },
    user() {
      return this.$store.state.user;
    },
  }
}
</script>

 

테스트

로그인 테스트를 하면 다음과 같은 결과를 확인할 수 있습니다.

 

MySQL의 user_authority 테이블에 관리자 권한을 추가합니다.

 

다시 로그인 테스트를 하면 관리자 메뉴가 추가된걸 보실 수 있습니다.

 

* 참고로 백엔드에서 admin 권한 체크를 하실때는 controller에 다음과 같이 데코레이터를 추가하시면 됩니다.

@UseGuards(AuthGuard,RolesGuard)
@Roles(RoleType.ADMIN)

 

반응형
반응형

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

https://youtu.be/QO1NunXmDuU

 

Jwt Token을 이용하여 frontend에서 로그인을 하는 방법을 알아보겠습니다.

 

Store 기능 사용하기

로그인 정보 저장을 위해 store를 사용하도록 합니다.

store 폴더 아래에 index.js 를 추가하고 다음 코드를 입력합니다.

/store/index.js

export const state = () => ({
    accessToken: {}
});

export const mutations = {
    accessToken (state, data) {
        state.accessToken = data;
    }
}

 

Navbar 만들기

Navbar를 만드는 다양한 방법이 있습니다. 이번엔 bootstrap vue를 이용하도록 합니다.

Nuxt 프로젝트에 bootstrap vue를 사용하는 방법은 다음 사이트를 참조하세요. https://bootstrap-vue.org/docs 

아래 명령으로 slider-front 프로젝트에 설치를 합니다.

yarn add bootstrap-vue

nuxt-config.js에 다음 설정을 추가합니다.

modules = {
  'bootstrap-vue/nuxt'
}

프로젝트에 layouts 폴더를 만들고 default.vue를 만듭니다.

bootstrap vue 사이트의 navbar 샘플을 복사하여 default.vue의 template에 붙여놓고 아래와 같이 변경합니다.

<template>
  <div>
  <b-navbar toggleable="lg" type="dark" variant="info">
    <b-navbar-brand href="#">Slider</b-navbar-brand>

    <b-navbar-toggle target="nav-collapse"></b-navbar-toggle>

    <b-collapse id="nav-collapse" is-nav>
      <b-navbar-nav class="ml-auto" v-if="!accessToken">
        <b-nav-item href="/login" right>로그인</b-nav-item>
      </b-navbar-nav>
      <b-navbar-nav class="ml-auto" v-if="accessToken && accessToken!==''">
        <b-nav-item @click="logout" right>로그아웃</b-nav-item>
      </b-navbar-nav>
    </b-collapse>
  </b-navbar>
  <nuxt/>
  </div>
</template>
<script>
export default {
  name: 'Layout',
  methods: {
    async logout() {
      await this.$store.commit('accessToken', '');
      await this.$router.push('/');
    }
  },
  computed: {
    accessToken() {
      return this.$store.state.accessToken
    }
  }
}
</script>

 

Login

기존 index.vue를 login.vue로 변경합니다.

index.vue를 만들고 다음과 같이 입력합니다.

index 페이지에서 로그인이 잘 되었는지를 확인하기 위해 accessToken을 보여주는 예제입니다.

/pages/index.vue

<template>
  <div>
    <div>Welcome!</div>
    <div v-if="accessToken">{{accessToken}}</div>
  </div>
</template>
<script>
export default {
  name: 'IndexPage',
  computed: {
    accessToken() {
      return this.$store.state.accessToken
    }
  }
}
</script>

로그인 API 호출 로직 수정

pages/kakao-callback.vue를 다음과 같이 수정합니다.

<template>
  <div>로그인중....</div>
</template>

<script>
  export default {
    async mounted() {
      try{
        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(
            '/auth/login', body, {}
        )
        if(response){
          console.log(response.accessToken);
          this.$store.commit('accessToken', response.accessToken);
        }
        return this.$router.push('/')
      }catch(error){
        console.log(error)
      }
    }
  }
</script>

프로젝트 실행화면

프로젝트를 실행하면 다음과 같은 화면을 보실 수 있습니다.

 

첫화면

 

로그인 화면

 

로그인 성공 후 화면

 

반응형
반응형

이번 시간은 JWT 인증 기능을 추가해 보겠습니다.

 

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

https://youtu.be/SClJMs2BlWk

 

 

JWT에 관한 자세한 사항은 제가 이전에 작성한 글을 참조해 주세요.

https://codegear.tistory.com/72

 

[Nodejs 프레임워크]NestJS - 12. JWT 토큰 생성

다음은 이글의 동영상 강의 입니다. https://youtu.be/H4VS-Osylvo 토큰을 이용한 API 호출 방법 REST API 호출시 토큰을 이용하면 사용자 인증과 권한을 체크할 수 있습니다. 다음 그림은 토큰의 생성과 호

codegear.tistory.com

 

JWT 관련 패키지 추가

jwt 인증을 위해서는 다음과 같은 패키지가 필요합니다.

- @nestjs/jwt

- @nestjs/passport

- passport

- passport-jwt

아래와 같이 패키지를 추가합니다.

yarn add @nestjs/jwt @nestjs/passport passport passport-jwt

 

Payload 인터페이스 생성

jwt인증시엔 payload interface가 필요합니다.

아래와 같이 같이 Payload interface를 만듭니다.(참조 : https://jwt.io/)

/src/auth/security/payload.interface.ts

export interface Payload {
    id: number;
    name: string;
    authorities?: any[];
}

JwtStrategy 를 아래와 같이 작성합니다.

/src/auth/security/passport.jwt.stategy.ts

import { Injectable, UnauthorizedException } from "@nestjs/common";
import { PassportStrategy } from "@nestjs/passport";
import { ExtractJwt, Strategy } from "passport-jwt";
import { AuthService } from "../auth.service";

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy){
    constructor(private authService: AuthService){
        super({
            jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
            ignoreExpiration: true,
            secretOrKey: process.env.JWT_SECRET
        })
    }
}

 

로그인 및 회원 가입

카카오 로그인 후에 회원 로그인 및 회원 가입을 처리합니다.

- 회원 데이터가 없을 경우는 회원 가입을 처리합니다.

- 회원 데이터가 있을 경우는 로그인 처리를 합니다.

 

우선 auth.controller에서 카카오 로그인을 한 후 다음 코드를 추가합니다.

/src/auth/auth.controller.ts

			console.log(`kakaoUserInfo : ${JSON.stringify(kakao)}`);
            if (!kakao.id) {
                throw new BadRequestException('카카오 로그인 실패!');
            }

            // 로그인 처리 - 회원 가입이 안되어 있을 경우 가입 처리
            const jwt =  await this.authService.login(kakao);
            console.log(`jwt.accessToken : ${jwt.accessToken}`);
            res.send({
                accessToken: jwt.accessToken,
                message: 'success'
            });

authService에서 고객을 조회하고, 로그인을 처리합니다.

/src/auth/auth.service.ts

async login(kakao): Promise<{accessToken: string} | undefined> {
	let userFind: User = await this.userService.findByFields({
            where: { kakaoId: kakao.id }
        });
        if(!userFind) {
            isFirstLogin = true;
            // 회원 가입
            const user = new User();
            user.kakaoId = kakao.id;
            user.email = kakao.kakao_account.email;
            user.name = kakao.kakao_account.name;
            
            userFind = await this.registerUser(user);
        }

        const payload: Payload = {
            id: userFind.id,
            name: userFind.name,
            authorities: userFind.authorities
        };
        return {
            accessToken: this.jwtService.sign(payload)
        };
}

userService에  findByFields, registerUser를 추가합니다.

/src/auth/user.service.ts

   constructor(
        @InjectRepository(User)
        private userRepository: Repository<User>,
        @InjectRepository(UserAuthority)
        private userAuthorityRepository: Repository<UserAuthority>,
    ){}
    
    async findByFields(options: FindOneOptions<User>): Promise<User | undefined> {
        return await this.userRepository.findOne(options);
    }
    
    async registerUser(newUser: User): Promise<User> {
        let userFind: User = await this.findByFields({
            where: { kakaoId: newUser.kakaoId }
        });
        if(userFind) {
            throw new HttpException('Username aleady used!', HttpStatus.BAD_REQUEST);
        }
        const registeredUser = await this.userService.save(newUser);
        if(registeredUser){
            await this.saveAuthority(registeredUser.id);
        }else {
            throw new HttpException('Username register error!', HttpStatus.INTERNAL_SERVER_ERROR);
        }

        return registeredUser;
    }
    
    async save(user: User): Promise<User | undefined> {
        return await this.userRepository.save(user);
    }
    
    async saveAuthority(userId: number): Promise<UserAuthority | undefined> {
        let userAuth = new UserAuthority();
        userAuth.userId = userId;
        userAuth.authorityName = RoleType.USER;
        return await this.userAuthorityRepository.save(userAuth);
    }

권한 Type을 선언한 RoleType을 만들어줍니다.

/src/auth/role-type.ts

export enum RoleType {
    USER = 'ROLE_USER',
    ADMIN = 'ROLE_ADMIN',
}

 

auth.module에 jwtModule을 추가하고 import 합니다.

/src/auth/auth.module.ts

import { JwtModule } from '@nestjs/jwt';
import { JwtStrategy } from './security/passport.jwt.strategy';
...
@Module({
  imports: [
    TypeOrmModule.forFeature([User]),
    JwtModule.register({
      secret: process.env.JWT_SECRET,
      signOptions: {expiresIn: '300s'},
    }),
    PassportModule
  ],
  exports: [TypeOrmModule, UserService],
  controllers: [AuthController],
  providers: [AuthService, UserService, JwtStrategy]
})
export class AuthModule {}

 

프론트에서 로그인을 하면 브라우저의 콘솔에서 아래와 같이 jwt token을 확인할 수 있습니다.

반응형
반응형

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

https://youtu.be/7sT3G9ZwyzM

 

카카오 로그인 기능을 만들어봅니다.

 

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

  1. 카카오 developer 사이트에서 application 생성
  2. 프론트 개발
  3. 백엔드 개발

보다 자세한 설명은 이전 영상을 보시면 됩니다.

https://www.youtube.com/watch?v=E-a-wQqybbE 

 

카카오 developer 사이트에서 application 생성

  • 우선 카카오 로그인을 사용하기 위해 https://developers.kakao.com/ 에서 로그인을 합니다.
  • 상단의 내 애플리케이션 메뉴를 클릭 합니다.

  • 애플리케이션 추가하기를 클릭합니다.

  • 애플리케이션 정보를 입력합니다.

  • 애플리케이션 목록에서 새로 만든 slider를 확인할 수 있습니다.

  • slider 앱을 클릭하면 앱에 대한 정보를 확인할 수 있습니다.

  • 플랫폼 -> 플랫폼 설정하기를 클릭합니다.

  • 우리는 Web으로 개발을 할 것이므로 web을 클릭합니다. 사이트 도메인에 http://localhost:3000 를 입력한 후 저장합니다.
    *http://localhost:3000 는 로컬에서 프론트를 개발하여 테스트 하기 위한 정보입니다.

  • 저장이 완료되면 다음과 같이 변경된것을 확인할 수 있습니다. 여기서 Redirect URI 등록하러 가기를 클릭합니다.

  • 활성화 설정은 ON 으로 변경하고, Redirect URI 등록을 클릭합니다. 

  • Redirect URI에 http://localhost:3000/kakao-callback 을 입력합니다.

  • Left 메뉴에서 카카오로그인 -> 동의 항목을 클릭합니다.

  •  동의 항목은 카카오 로그인시 가져올 수 있는 고객의 정보를 선택하는 화면입니다.

  • 설정 항목을 클릭한 후 필수 또는 선택 동의로 변경하고, 저장합니다.
    * 필수 동의(검수 필요)가 disable되어 있는 경우는 비즈니스 채널을 신청해야만 선택할 수 있습니다.

  • 카카오 애플리케이션 설정이 완료되었습니다.

프론트 개발

  • 다운로드 받은 이미지를 프로젝트의 /static/images/kakao_login.png로 복사합니다.
  • 카카오 로그인 모듈을 사용하기 위해 
    /nuxt.config.js 의 head 부분에 다음을 추가합니다.
script: [
  {
    src: 'https://developers.kakao.com/sdk/js/kakao.js'
  }
]
  • index page를 수정합니다.
    /pages/index.vue
<template>
  <a @click="loginWithKakao">
    <img src="/images/kakao_login.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>
  • callback 페이지를 추가합니다.
    /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}`)
      // 서버 로그인 요청(kakao 인증 코드 전달)
      const body = {
        code: this.$route.query.code,
        domain: window.location.origin
      }
      const response = await this.$axios.$post(
        '/auth/login', body, {}
      )
      console.log(response)
    } catch (error) {
      console.log(error)
    }
  }
}
</script>
  • 이제 프론트를 실행하고 테스트 해봅니다.
yarn dev
  • 카카오 로그인 버튼을 클릭합니다.

  • 동의 화면이 나오고 동의 체크 후

  • 크롬의 콘솔을 실행해보면 code 값이 찍힌 것을 확인할 수 있습니다.

백엔드 개발

  • slider-api 프로젝트를 open 합니다.
  • 포트 변경 - frontend에서 3000번 포트를 사용하고 있으므로, backend 포트를 3003으로 바꿔주겠습니다.
    /src/main.ts
  await app.listen(3003);
  • front의 호출 url도 http://localhost:3003으로 변경합니다.
    /nuxt.config.js
axios: {
	baseURL: 'http://localhost:3003'
},
  • 카카오 api 호출을 위해 axios 패키지를 추가합니다.
yarn add axios
  • generator로 auth module/controller/service를 생성합니다.
nest g module auth
nest g controller auth
nest g service auth
  • authController에 다음을 추가합니다.
    src/auth/auth.controller.ts
import { Controller, Post, Body, Response, BadRequestException, UnauthorizedException } from '@nestjs/common';
import { AuthService } from './auth.service';

@Controller('auth')
export class AuthController {
    constructor(
        private authService: AuthService
    ){}
    @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.authService.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();
        }
    }
}
  • authService에 다음을 추가합니다.
    /src/auth/auth.service.ts
import { Injectable, UnauthorizedException } from '@nestjs/common';
import axios from 'axios';
import * as qs from 'qs';

@Injectable()
export class AuthService {
    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();
        }
      }
}

* kakaoKey는 kakao developers 사이트에서 생성한 RestAPI 키를 입력합니다.

  • 브라우저에서 http://localhost:3000을 입력하고 로그인을 해보면 다음과 같이 CORS 오류를 만나게 됩니다.

  • CORS를 해결하기 위해 main.ts에 설정을 추가합니다.
    /src/main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  const whitelist = [
    'http://localhost:3000'
  ];
  app.enableCors({
    origin: function (origin, callback) {
      if (!origin || whitelist.indexOf(origin) !== -1) {
        callback(null, true)
      } else {
        callback(new Error('Not allowed by CORS'))
      }
    },
    allowedHeaders: '*',
    methods: "GET,PUT,PATCH,POST,DELETE,UPDATE,OPTIONS",
    credentials: true,
  });
  await app.listen(3003);
}
bootstrap();
  • 다시 브라우저에서 로그인을 시도합니다.
    로그인이 완료되면 크롬 콘솔에서 다음과 같은 로그를 확인할 수 있습니다.

카카오 로그인이 완료되었습니다.

 

다음 시간에는 로그인에 JWT 인증을 추가하는 것을 진행합니다.

반응형

+ Recent posts