회원가입, 로그인 구현React+REST API 게시판 구현/BE - TypeORM2021. 9. 24. 23:33
Table of Contents
참고
회원가입 & 로그인 API 설계
- 우선 위 링크를 참고해서 entity를 설계하자
- /api/auth/signin - 회원가입 API url
- /api/auth/signup - 로그인 API url
- 우선 패스워드를 암호화할 모듈과 jwt 모듈을 설치하자.
yarn add bcryptjs @types/bcryptjs
yarn add jsonwebtoken @types/jsonwebtoken
컨트롤 모듈화
- src 아래 controller 폴더에 AuthController.ts 파일을 만들고 프로토타입을 만들자.
import {User} from "../entity/User";
import {Role} from "../entity/Role";
import {getConnection} from "typeorm";
export class AuthController {
}
라우팅 모듈화
- /api/auth/[~] 경로를 가진 API를 만들기 전에 /api/auth를 처리해줄 라우팅 부분을 모듈화하자.
- src 아래 router 폴더에 auth.ts 파일을 만들자
- 우선 /auth를 처리해줄 라우팅을 모듈화하자.
src/router/auth.ts
import {Router} from "express";
import {AuthController} from "../controller/AuthController";
const routes = Router();
export default routes;
- 이제 /api를 처리해주는 라우팅 모듈인 src/router/index.ts 파일에 서브라우팅을 추가하자.
src/router/index.ts
import {Router} from "express";
...
// src/router/auth.ts 라우팅 모듈
import auth from "./auth";
const routes = Router();
...
routes.use('/auth', auth);
export default routes;
- 마지막으로 src/index.ts에서 /api를 처리해주자.
src/index.ts
import express from 'express';
import {createConnection} from "typeorm";
// 라우터 모듈
import routes from "./router";
let app = express();
// x-www-form-urlencoded를 파싱
app.use(express.urlencoded({
extended: true
}))
// body-parser는 내장되어있음. json 파싱하기 위해서 설정만 추가
app.use(express.json());
app.use('/api', routes)
createConnection().then(connection => {
app.listen(8080, () => {
console.log('server is listening 8080');
});
});
회원가입 API
- HTTP 메서드: POST
- url: /api/auth/signup
- body에 이메일, 비밀번호, 사용자 이름, 권한(role)을 받아서 사용자 정보를 생성한다. 권한(role)은 body에 넣어서 보냈다면 설정하고 만약 넣지 않았다면 ROLE_USER를 기본 권한으로 설정한다.
- 이미 존재하는 이메일이나 닉네임을 요청으로 보내면 DB에 저장하지 않고 클라이언트에게 응답으로 에러메시지를 보낸다
컨트롤 모듈화
src/controller/AuthController.ts
import {compareSync, hashSync} from "bcryptjs";
import {User} from "../entity/User";
import {Role} from "../entity/Role";
import {getConnection} from "typeorm";
export class AuthController {
static signUp = async (req, res) => {
const {email, password, username, roles} = req.body;
const user = new User();
user.email = email;
// 패스워드 복호화
user.password = hashSync(password, 8);
user.username = username;
// 이메일 중복 체크
const existUser = await getConnection().getRepository(User)
.findOne({where: {email}});
if (existUser) {
return res.status(400).send({ message: "이미 존재하는 이메일입니다" });
}
// 닉네임 중복 체크
const existUsername = await getConnection().getRepository(User)
.findOne({where:{username}});
if (existUsername) {
return res.status(400).send({message: "이미 존재하는 닉네임입니다"});
}
user.roles = [];
// body에 role을 넣으면 설정해주고 그렇지 않으면 디폴트로 'ROLE-USER'로 설정
if (roles && roles.length > 0) {
// where a 혹은 b or 조건 [{ name: 'a'}, {name: 'b'}]
const res = await getConnection().getRepository(Role).find({
where: roles.map(name => ({name}))
})
user.roles = res;
} else {
// 기본 role은 USER
const res = await getConnection().getRepository(Role).find({
where: {name: 'ROLE_USER'}
})
user.roles = res;
}
const result = await getConnection().getRepository(User).save(user);
res.send(result);
}
}
라우팅 모듈화
src/router/auth.ts
import {Router} from "express";
import {AuthController} from "../controller/AuthController";
const routes = Router();
routes.post('/signup', AuthController.signUp);
export default routes;
- email: "qkwl521@naver.com", password: "12345678", username: "duckgugong"을 json 형식으로 body에 넣어서 post 메서드를 이용하면 정상적으로 DB에 반영이 된디!
로그인 API
- HTTP 메서드: POST
- url: /api/auth/signin
- body에서 이메일, 패스워드를 입력받아서 체크하는 API이다. 해당 사용자의 이메일이 있는지 체크한 후 패스워드가 맞는지 체크한다. 패스워드는 복호화가 불가능하므로 compareSync 함수를 이용하여 비교한다.
- 로그인시 jwt 토큰을 생성해서 리턴한다. 토큰 생성시 secret key와 expire 시간을 설정해야 하는데 .env 파일에 생성한다.
secret=11112222
expirationSecondMs=86400000
- registered claims인 jti에는 사용자 id를 넣었고 그밖에 필요한 것들은 private claims로 정의해서 넣는다. roles는 여러개가 가능하므로 스트링 배열 형태로 넣는다.
jwt 토큰이란?
- JWT 는 JSON Web Token의 약자로 전자 서명 된 URL-safe (URL로 이용할 수있는 문자 만 구성된)의 JSON이다.
- 전자 서명은 JSON 의 변조를 체크 할 수 있게되어 있다.
- JWT는 속성 정보 (Claim)를 JSON 데이터 구조로 표현한 토큰으로 RFC7519 표준이다.
- JWT는 서버와 클라이언트 간 정보를 주고 받을 때 Http 리퀘스트 헤더에 JSON 토큰을 넣은 후 서버는 별도의 인증 과정없이 헤더에 포함되어 있는 JWT 정보를 통해 인증한다.
- 이때 사용되는 JSON 데이터는 URL-Safe 하도록 URL에 포함할 수 있는 문자만으로 만든다.
- JWT는 HMAC 알고리즘을 사용하여 비밀키 또는 RSA를 이용한 Public Key/ Private Key 쌍으로 서명할 수 있다.
컨트롤 모듈화
src/controller/AuthController.ts
import {compareSync} from "bcryptjs";
import {User} from "../entity/User";
import {Role} from "../entity/Role";
import {getConnection} from "typeorm";
import jwt from 'jsonwebtoken';
export class AuthController {
...
static signIn = async (req, res) => {
const {email, password} = req.body;
const user = await getConnection().getRepository(User)
.findOne({relations: ["roles"], where: {email}});
if (!user) {
return res.status(400).send({ message: "존재하지 않는 이메일입니다" });
}
if (!compareSync(password, user.password)) {
return res.status(400).send({ message: "비밀번호가 일지하지 않습니다" });
}
// token 생성
const token = jwt.sign({ jti: user.id, email: user.email, roles: user.roles.map(role => role.name) },
process.env.secret, {
subject: user.username,
algorithm: 'HS512',
expiresIn: process.env.expirationSecondMs
});
res.send({jwt: token});
}
}
라우팅 모듈화
src/router/auth.ts
import {Router} from "express";
import {AuthController} from "../controller/AuthController";
const routes = Router();
...
routes.post('/signin', AuthController.signIn)
export default routes;
- 위에서 만든 회원가입 정보로 로그인을 하면 정상적으로 jwt 토큰이 리턴된다!
'React+REST API 게시판 구현 > BE - TypeORM' 카테고리의 다른 글
board, comment 인증 로직 적용하기 + 추가구현 (0) | 2021.09.26 |
---|---|
미들웨어 설정 + 추가 라우팅 (0) | 2021.09.26 |
인증과 권한 설계 (0) | 2021.09.24 |
commet CRUD API (0) | 2021.09.24 |
board에 image 추가하기 (0) | 2021.09.24 |
@덕구공 :: Duck9s'
주니어 개발자에욤
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!