[모두의 이력서_6일차] Auth 기능 및 로그아웃 기능
처음으로 혼자서 프론트부터 백까지 하는 프로젝트이다 보니 정확하지 않을 수 있습니다!
Auth 기능 만들기
Auth(인증)를 만드는 이유
- 페이지 이동 때마다 로그인되있는지 안되어 있는지, 관리자 유저인지 등을 체크하기 위해
- 글을 쓸때나 지울 때 같은 경우 권한이 있는지도 체크하기 위해
현재 서버는 DB에 토큰을 넣어주었고 클라이언트는 Cookie에 토큰을 넣어주었습니다.
이 서버, 클라이언트에 있는 토큰이 같은 토큰인지 체크해 줘야 됩니다.
// jsonwebtoken을 사용해서 토큰 생성
const token = jwt.sign(user._id.toHexString(), "secretToken");
클라이언트에 쿠키에 담겨있는 토큰을 서버에 전달하면 서버쪽 토큰이 인코드 하면 User ID가 나옵니다.
jwt로 user._id + 'secretToken'조합으로 토큰을 만들면 token의 디코드를 통해 user._id를 추출해서
해당 아이디를 가진 유저의 DB에 같은 토큰이 존재하는지 확인하면 Auth(Authentication_인증) 기능을 구현할 수 있습니다.
(user._id + 'secretToken' = token에서 token, 'secretToken'을 가지고 user._id를 찾을 수 있습니다.)
1. Cookie에서 저장된 Token을 Server에서 가져와서 복호화(디코드)를 한다.
유저정보를 가져올 라우터 만들기
// server.ts
app.get("/api/user/auth", auth, (req, res)=>{
});
이번에 라우터를 만들때 미들웨어를 만들어야 됩니다.
auth: 미들웨어
미들웨어: 엔드포인트로 reqest를 받고 난 다음에 callback함수 하기 전에 중간에 무언가를 하는 것을 의미
폴더 만들기
back
|- middleware
|- auth.ts
// auth.ts
export const auth = (req, res, next) => {
// 인증 처리 하는 곳
// 1.클라이언트 쿠키에서 토큰을 가져온다.
// 2.토큰을 복호화 한 후 유저를 찾는다.
// 3.유저가 없으면 인증 No!
// 4.유저가 있으면 인증 OKay!
};
https://www.npmjs.com/package/jsonwebtoken
jsonwebtoken
JSON Web Token implementation (symmetric and asymmetric). Latest version: 9.0.0, last published: 3 months ago. Start using jsonwebtoken in your project by running `npm i jsonwebtoken`. There are 23121 other projects in the npm registry using jsonwebtoken.
www.npmjs.com
// verify a token symmetric
jwt.verify(token, 'shhhhh', function(err, decoded) {
console.log(decoded.foo) // bar
});
이 부분을 참고해서 user.ts에 작성하겠습니다.
// User.ts
userSchema.statics.findByToken = function (token, cb) {
const user = this;
// 토큰을 decode 한다.
// decode를 해서 user._id를 찾아야 된다.
jwt.verify(token, "secretToken", function (err: any, decoded: any) {
// 유저 아이디를 이용해서 유저를 찾은 다음에
// 클라이언트에서 가져온 token과 DB에 보관된 토큰이 일치하는지 확인
user.findOne(
{ _id: decoded, token: token },
function (err: "empty", user: any) {
if (err) return cb(err);
cb(null, user);
}
);
});
};
2. 복호화를 하면서 나온 User ID를 이용해서 DB User Collection에서 유저를 찾은 후 쿠키에서 받아온 token이 유저도 갖고 있는지 확인
쿠키가 일치 X -> Authentication False !!
쿠키가 일치 O -> Authentication True!! 그리고 그 해당하는 유저의 정보들을 선별
// auth.ts
import { User } from "./../models/User";
export const auth = (req: any, res: any, next: any) => {
// 인증 처리 하는 곳
// 1.클라이언트 쿠키에서 토큰을 가져온다.
let token = req.cookies.x_auth;
// 2.토큰을 복호화 한 후 유저를 찾는다.
User.findByToken(token, (err: any, user: any) => {
if (err) throw err;
// 3.유저가 없으면 인증 No!
if (!user) return res.json({ isAuth: false, error: true }); // 클라이언트에게 {isAuth: false, error: true} 전달
// 4.유저가 있으면 인증 OKay!
req.token = token;
req.user = user;
next(); // server.ts auth 미들웨어가 갈 수 있게 next를 안쓰면 미들웨어에 갇쳐버린다.
});
};
// server.ts
app.get("/api/user/auth", auth, (req, res) => {
// 여기까지 미들웨어를 통과해 왔다는 얘기는 Authentication이 True라는 말
res.status(200).json({
_id: req.user._id,
isAdmin: req.user.role === 0 ? false : true,
isAuth: true,
email: req.user.email,
name: req.user.name,
lastname: req.user.lastname,
role: req.user.role,
image: req.user.image,
});
});
마지막으로 User.ts에서 findOne이 콜백지원을 안 하기 때문에 고쳐줘야 됩니다.
userSchema.statics.findByToken = function (token, cb) {
const user = this;
jwt.verify(token, "secretToken", function (err: any, decoded: any) {
// 유저 아이디를 이용해서 유저를 찾은 다음에
// 클라이언트에서 가져온 token과 DB에 보관된 토큰이 일치하는지 확인
// 수정 후
user
.findOne({ _id: decoded, token: token })
.then((user: any) => {
return cb(null, user);
})
.catch((err: "empty") => {
return cb(err);
});
// 수정 전
// user.findOne(
// { _id: decoded, token: token },
// function (err: "empty", user: any) {
// if (err) return cb(err);
// cb(null, user);
// }
// );
});
};
post man으로 확인
로그아웃 기능
1. 로그아웃 Route 만들기
// server.ts
app.get('/api/users/logout', auth, (req, res)=>{
// 로그아웃 하려는 유저를 데이터베이스에서 찾아서 데이터를 업데이트
})
2. 로그아웃 하려는 유저를 DB에서 찾아서 그 유저의 토큰을 지원 준다.
server.ts
app.get("/api/users/logout", auth, (req: any, res) => {
// 로그아웃 하려는 유저를 데이터베이스에서 찾아서 데이터를 업데이트
User.findOneAndUpdate(
{ _id: req.user._id },
{ token: "" },
(err: "empty", user: any) => {
if (err) return res.json({ success: false, err });
return res.status(200).send({
success: true,
});
}
);
});
이번에도 findOneAndUpdate가 콜백지원을 안 함으로 고쳐줘야 됩니다.
app.get("/api/users/logout", auth, (req: any, res) => {
// 로그아웃 하려는 유저를 데이터베이스에서 찾아서 데이터를 업데이트
// 수정후
User.findOneAndUpdate({ _id: req.user._id }, { token: "" })
.then(() => {
return res.status(200).send({
success: true,
});
})
.catch((err: "empty") => {
return res.json({ success: false, err });
});
// 수정전
// User.findOneAndUpdate(
// { _id: req.user._id },
// { token: "" },
// (err: "empty", user: any) => {
// if (err) return res.json({ success: false, err });
// return res.status(200).send({
// success: true,
// });
// }
// );
});
post man으로 확인
몽고디비 확인
token: ""이 되었습니다-!
참고자료
https://www.youtube.com/watch?v=OGVsnbEbSLM
https://www.youtube.com/watch?v=zye0VrVUfuI&t=1s