LeChuck

SNS 서비스 실습

·4 min to read

SNS 앱 NodeBird

  • 로그인

  • 이미지 업로그

  • 게시글 작성

  • 해시태그 검색

  • 팔로잉

프로젝트 구조

route

routes/page.js GET / -> render main.html GET /profile -> render profile.html GET /join -> render join.html

routes/auth.js GET /auth/logout -> GET /auth/kakao ->

POST /auth/join -> POST /auth/login ->

routes/post.js POST /post -> 게시글 업로드. POST /post/img -> 이미지 업로드. multer upload.single()

\
\--- config/config.json
\--- models/index.js
\---		hashtag.js
\---		post.js
\---		user.js
\--- passport/index.js
\---		kakaoStrategy.js
\---		localStrategy.js
\--- public/main.css
\--- routes/auth.js
\---		middlewares.js -> 로그인/로그아웃 접근권한 제어 미들웨어
\---		page.js
\---		post.js
\---		user.js
\--- views/main.html
\---		error.html
\---		layout.html
\---		join.html
\---		profile.html

MySQL 세팅하기

로그인 - user table

게시글 - post table

해시태그 - hashtag table

테이블간 관계

NodeBird 프로젝트 내 모델은 총 다섯개다. 직접 생성한 User, Hashtag, Post 모델이 있고, 모델간 관계를 통해 파생된 PostHashtag, Follow 모델이 있다.

팔로잉은 같은 테이블간 N:M 관계를 맺는다.

User can follow A,B,C

A,B,C can be User's follower

N:M 관계로 파생된 Follow 모델(테이블)에는 db.sequelize.models.Follow와 같은 방식으로 접근할 수 있다.

  • user.getPosts(), user.addPosts()

  • post.getHashtags(), post.addHashtags()

  • hashtags.getPosts(), hashtags.addPosts()

Passport를 이용한 로그인 구현

Passport.js

패스포트는 인증(Authentication)과 인가(Authorization)를 쉽게 해주는 Node.js 미들웨어다. 패스포트는 요청(req)을 인증(Authenticate)하기 위한 목적으로 설계되었다. 패스포트는 인증 과정을 깔끔하게 캡슐화하여 디테일한 부분은 위임하고, 개발이 편리해지게끔 돕는다.

패스포트는 아래와 같은 간단한 명령문을 통해 인증 과정에서의 복잡성을 줄였다.

app.post('/login/password', passport.authenticate('local'));

위 명령문 뒤에 숨어있는 핵심 콘셉트는 다음과 같다.

  • middleware

  • startegies

  • sessions

passport.authenticate()는 request를 authenticate하기 위한 middleware다. strategy에 의해 인증이 성공했을 경우 req.user 속성에 인증된 유저 정보가 세팅되고, session이 생성된다.

인증 메커니즘은 strategy에 의해 구현된다. passport-local이라는 대표적인 strategy는 username과 password로 사용자를 인증하지만, 다른 strategy에서는 username과 password 외의 것으로 인증 메커니즘을 구현할 수가 있는 것이다.

strategy 설치 및 configure

패스포트 strategy는 npm을 통해 설치할 수 있다.

npm i passport passport-local passport-kakao bcrypt

패스포트 strategy를 설치했으면 configuration 과정을 밟아야 한다. localStrategy 생성자는 함수를 인자로 전달받는데 이를 verify function이라고 부른다. verify function은 db query를 통해 유저 자격을 검증하고, callback 함수 done(user)을 호출한다. 검증된 user 정보를 done() 콜백 함수에 전달해서 이후 req.login(user) 명령이 가능하게 한다.

strategy를 configure했으면, .use를 통해 register해야 한다.

// app.js
const passportConfig = require('./passport');
 
passportConfig();
 
app.use(passport.initialize());
app.use(passport.session());

register가 완료되면, passport.authenticate(strategy 이름)과 같이 authenticate() 미들웨어의 첫 번째 인수로 strategy를 전달하여 사용할 수 있다.

로그인 과정 개요

  1. HTML <form>에서 POST/ auth/login로그인 요청 (views/layout.html)

  2. 라우터에서 passport.authenticate(local, callback) 메서드 호출. local Startegy를 수행한 후 성공 or 실패시 callback을 실행한다. (routes/page.js)

  3. local Strategy에서는 사용자가 HTML form에 입력한 정보가 유효한 정보인지 DB와 대조해보고 대조에 성공하면 해당 회원정보(exUser)를 done() 콜백함수의 인자(user)로 전달해서 authenticate의 두 번째 인자인 callback을 실행한다. (passport/localStrategy.js -> routes/page.js)

  4. callback에서는 req.login(user)를 수행한다. login 메서드는 passport가 req에 추가한 것. req.login()passport.serializeUser(user)를 호출한다.

  5. passport.serializeUser()에서는 전달받은 user를 req.session에 추가한다.

  6. 로그인 완료

로그인 이후의 과정

  1. 요청이 들어온다

  2. 라우터에 요청이 도달하기 전에 passport.session 미들웨어가 passport.deserializerUser() 메서드를 호출한다

  3. req.session에 저장된 아이디로 db에서 사용자를 조회한다

  4. 조회된 사용자 정보를 req.user에 저장한다

  5. 라우터에서 req.user 객체 사용이 가능해진다.

local login

로컬 로그인이란 다른 SNS 서비스를 통해 로그인하지 않고 자체적으로 회원가입 후 로그인하는 방식.

로그인/로그아웃 상태에 따른 접근 권한 부여

Passport는 req 객체에 req.isAuthenticated()라는 메서드를 부여한다. 로그인 중이면 req.isAuthenticated()의 값이 true이고, 로그아웃 중이면 false다. 따라서 이 메서드로 로그인 여부를 파악할 수 있다.

  • 로그아웃 라우터, 이미지 업로드 라우터 -> 로그인한 사람만 접근 가능

  • 회원가입 라우터, 로그인 라우터 -> 로그인하지 않은 사람만 접근 가능

isLoggedIn, isNotLoggedIn 미들웨어를 만들어서 page, auth 등의 라우터에 적용하자. 이를테면, router.post() 미들웨어를 통해 POST /login 같은 HTTP 요청을 보낼 때 router.post(path, isNotLoggedIn)와 같이 사용하여 로그인하지 않은 유저만 POST login 요청을 보낼 수 있도록 만들자.

kakao login

SNS 로그인은 첫 로그인한 경우에 한해 회원가입 처리를 하고, 두 번째 로그인부터는 로그인 처리를 해야 한다.