전 게시글 확인!
passport는 Node에서 로그인을 처리하기 위한 모듈이다.
간단하게 생각해서 여권이라고 생각하면 되는 데, 서비스를 개발하면 로컬 유저만 있는 경우도 있지만, 구글과 카카오 등 oauth를 이용한 다양한 종류의 유저를 처리해야할 때가 있는 데 이 때 passport를 사용하면 편리하다.
로그인 할 때 나라별 여권이 있는 것처럼, 로컬인지 카카오인지 등의 유저 종류에 따라서 로그인 로직을 쉽게 나눌 수 있는 장점이 있다.
1. 필요한 모듈 설치
먼저 passport 개발을 위해 필요한 모듈을 아래와 같이 설치하자.
- passport, @types/passport : passport 설정을 위한 모듈
- passport-local, @types/passport-local : 로컬 로그인을 위한 passport 모듈
- jsonwebtoken, @types/jsonwebtoken : jwt 관련 모듈
npm install passport passport-local jsonwebtoken
npm install --save-dev @types/passport @types/passport-local @types/jsonwebtoken
2. passport 셋팅
passport 셋팅을 해주기 위하여 먼저 src/index.ts에서 아래와 같이 passport를 위한 코드를 추가해준다!
passport 설정을 담은 PassportConfig를 가져와 실행 시키고, passport 사용을 위한 passport.initalize를 이용하여 설정한다.
// src/index.ts
import express from 'express'
import passport from 'passport'
import sequelize from './models'
const app = express()
// passport 파일 가져오기
const PassportCofig = require('./utils/passport')
// passport 실행
PassportCofig()
app.use(express.json())
app.use(express.urlencoded({ extended: false }))
// passport 설정
app.use(passport.initialize())
app.use('/api', require('./api'))
const port: number = 3000
app.listen(port, async () => {
console.log(`SERVER ON! PORT : ${port}`)
await sequelize
.authenticate()
.then(async () => {
console.log('connection success')
})
.catch((e) => {
console.log(e)
})
})
3. passport 설정 파일 작성
src에 utils 폴더를 만들고 passport 폴더와 그 안에 index.ts를 생성한다.
해당 파일에는 passport 종류에 따른 분기처리를 하는 코드라고 생각하면 된다.
일단 passport-local, 로컬 로그인만 작성해준다.
// src/utils/passport/index.ts
import passportLocal from 'passport-local'
import passport from 'passport'
import { User } from '../../models/domain/User'
import * as bcrypt from 'bcrypt'
// passport-local 설정
const LocalStrategy = passportLocal.Strategy
module.exports = () => {
// passport에서 "local"이면 해당 로직으로 들어옴.
passport.use(
new LocalStrategy(
{
usernameField: 'email',
passwordField: 'password',
},
// Local Login 처리 로직
async (email: any, password: any, done: any) => {
try {
// sequelize를 이용해 email를 검색해 유저를 조회한다.
const findUser = await User.findOne({ where: { email: email } })
// 유저가 없으면 없는 회원이라는 실패 로직 처리
if (!findUser)
done(null, false, { message: '가입되지 않은 회원 입니다.' })
else {
// 유저가 있으면 비밀번호를 암호화 해제를 해본다.
const result = await bcrypt.compare(password, findUser.password)
result
? done(null, findUser) // 비밀번호 일치하면 로그인 성공
: done(null, false, { message: '비밀번호가 일치 하지 않음' }) // 일치 안 하면 실패
}
} catch (err) {
console.error(err)
// 에러 로직
done(err)
}
},
),
)
}
4. Local Login 작성
이제 user.service에 아래의 코드를 작성하자.
localLogin 함수는 passport-local를 호출하는 코드라고 생각하면 된다.
로그인이 성공하면, 유저의 idx를 이용하여 jwt를 생성하고 cookie에 담아서 보낸다.
// src/api/user/user.service.ts
import { Response, Request } from 'express'
import { User } from '../../models/domain/User'
import * as bcrypt from 'bcrypt'
import { Provider } from '../../models/interface/User.interface'
import passport from 'passport'
import jwt from 'jsonwebtoken'
exports.saveUser = async (req: Request, res: Response) => {
try {
const { email, password, name } = req.body
const hash = await bcrypt.hash(password, 10)
const saveUser = await User.create({
email,
password: hash,
name,
provider: Provider.LOCAL,
})
res.json({ result: true, user: saveUser })
} catch (err) {
console.log(err)
}
}
// Local Login
exports.localLogin = async (req: Request, res: Response) => {
// passport-local로 전송
passport.authenticate('local', { session: false }, (err, user) => {
// passport-local 결과에서 Err가 있거나, 유저가 없을 때
if (err || !user) {
return res.status(400).json({
message: 'Something is not right',
user: user,
})
}
// 로그인 후 코드 작성
req.login(user, { session: false }, (err) => {
// err 있을 때 처리
if (err) {
console.log(err)
res.send(err)
}
// jwt를 이용하여 token을 생성
const token = jwt.sign({ idx: user.idx }, '123')
// cookie에 accessToken에 token을 담아서 저장
res.cookie('accessToken', token, {
expires: new Date(Date.now() + 86400e3),
sameSite: 'lax',
})
// user 정보 리턴
return res.send({ user })
})
})(req, res)
}
그리고 /src/api/user/index.ts에서 라우팅 처리까지 해주면 끝이다.
// src/api/user/index.ts
const router = require('express').Router()
const user = require('./user.service')
router.post('/', user.saveUser)
//Local Login 추가
router.post('/local', user.localLogin)
module.exports = router
export {}
Postman으로 API를 실행하면 쿠키도 잘 담겨오고 실행도 잘 되는 것을 볼 수 있다.
'B.E > Node JS' 카테고리의 다른 글
Express + routing-controllers + typedi를 사용한 서버 구축하기(1) - Routing Controller (0) | 2023.10.12 |
---|---|
[Node JS] Node JS란? (0) | 2022.11.14 |
[Node JS] typescript + sequelize + passport로 유저 API 개발 - Local User 생성 (0) | 2022.09.29 |
[Node JS] typescript + sequelize + passport로 유저 API 개발 - Sequelize 셋팅 (0) | 2022.09.29 |
[Node JS] Node.js를 Typescript 프로젝트로 셋팅하기. (0) | 2022.09.29 |