Wecode 부트캠프 -Foundation 2/인증, 인가 - 실습 (회원가입, 로그인)

Foundation Test를 위한, [백엔드 프론트 연결] 프론트엔드에게 '로그인' 시키기

JBS 12 2023. 9. 7. 20:40

 

 

[jwt, token] 토큰 개념, 토큰 코드 만들기, 토큰 발행 / 프론트와 연결하는 법 (엔드포인트, api)

토큰? 백엔드가 매번 프론트에게 사용자의 로그인 기록을 주는데, 비밀번호를 암호화해서 줌 --> 로그인 기록 유지 하는 기능 (다른 거 하는 동안) 로그인 성공한 시점에 토큰을 발급. 그 토큰의

pm-developer-justdoit.tistory.com

 

프론트엔드에게 회원가입 정보 받기

프론트와 백엔드 연결 (회원가입) 회원가입으로 프론트와 백엔드를 연결해볼 것이다. 백엔드 입장에서만 썼는데, 프론트는 무엇을 하는가를 생각해보는 시간. http 통신과 인터넷에 대한 이해가

pm-developer-justdoit.tistory.com

로그인도 시도해볼까?

아직 지금은 하드코딩이긴한데 (id를 넣어놓아서, 누가 로그인 해도 다 되게) 

어쨌든 로그인 되는지 보려는데

 

그럼 되는지 어떻게 알지?

 

프론트엔드 분 컴퓨터에서 로그인이 되면 되는데, 

백엔드가 로그인이 안 되면 날리는 메세지를 설정해놓았으니까

 

1) 비번 패스워드 잘못쳐도 로그인 돼야 하고

2) 비번 패스워드 잘 쳐도 로그인 돼야 id  디폴트 빼고 다 문제 없는 것

 

 

(회원가입 로그인 과정에서 만약 오류가 난다면,

다른 백엔드 ip로도 프론트가 해보고 되면 ★이전 백엔드 코드 문제이고

다른 백엔드로 했을 때  안 되면, 프론트 문제

 

vice versa)


프론트엔드 분이 로그인이 안 된다고 해서, 

혹시 서버가 꺼져있나 하고 

 

저장 command+ s 후

서버 끄고 ctrl+s 

다시 node app3.js로 실행하고

 

내 컴퓨터에서 해보았다. 

(ip 주소 대신 Localhost로)

 

postman 들어가서 

ip주소를 localhost로 수정하고, 

 

 

login success!


내꺼에서는 됐으니 

다시 프론트엔드 분에게 로그인 요청해보기! 

 

 

그런데 이상하게, 

 

프론트엔드 분 컴퓨터에서 

로그인은 되는데,....

 

메세지가 usercreated로 

회원가입에서 설정한 메세지가 뜬다....

 

 

나 login message 잘 썼는데

회원가입 메세지와 헷갈리지 않았는데 

 

[로그인 코드]

// 오류 난 시점은 위에는 오류 없다는거 한줄씩 내려오는거니까. 서버는 항상 돌아가야 postman에서 작동 가능한데, 코드 수정 후에는 저장 후에,ctrl+c로 서버 중단 후에 다시 node 로 실행 후에 postman 실행- terminal 와서 결과 확인
// [로그인]
app.post("/login", async (req, res) => {
// postman에 http://localhost:8000/login 치는거) 8000는 아래 server 번호 참고 -> postman에 send 후에 터미널에서 확인
try {
const email = req.body.email;
const password = req.body.password;
// { email, password } = req.body

// email, password KEY_ERROR 확인
if (email === undefined || password === undefined) {
// ||는 or , 반대는 &&
const error = new Error("KEY_ERROR");
error.statusCode = 400;
throw error;
}

// 1. Email 가진 사람 있는지 확인
// if 없으면 -> Error
// 있으면 -> 정상 진행 (if 문 필요 없음)
const existingUser = await myDataSource.query(`
SELECT id, email, password FROM users WHERE email='${email}';
`); //sql문은 백엔드까지만 보내고, DB에는 안 보냄 (프- 백- DB)
// sql에서 email만 가져와도 되는데, 2번에서 해당 email에 해당되는 password를 가져와야하니까, 여기에서 한꺼번에 써주는것/ id, email, password를 가져와라. 변수 email이 문자열'적은 email'에 해당되는 것으로

console.log("existing user:", existingUser);

// email 없으면 에러 = 중복 없을 떄
if (existingUser.length === 0) {
// existing user 이용해서 판별`
const error = new Error("DUPLICATED_EMAIL_ADDRESS");
error.statusCode = 400;
throw error;
}

// 2. Password 비교 (로그인떈 해야함. 같아야 하니까 무조건)
// 유저가 입력한 password === DB에서 가져온 PASSword
// if 다르면 -> Error
// 같으면 -> 정상 진행. if 필요없음

//2-1.아무나의 패스워드가 아니라, 위에 친 이메일 소유자에 해당되는 패스워드여야 함
//2-2.데이터베이스에 있는 패스워드가, 지금 친 패스워드랑 같은지 확인 / 그러려먼, 지금 친 패스워드와 이메일 출력

console.log("existing user:", existingUser); //"existingUser:"는 문자열로 나오고, existingUser는 변수로 나오고/
console.log("email", "password"); //값을 찍어내는 게 아님, 들어오고 있는지 확인하려고/ 우리가 확인 한거 // 'password'는 텍스트, 아래에 있는 password는 변수
// //existingUser 는 객체로 key:value로 나오고, 그 안에 배열이 들어감, existingUser[0]={id: 5, email: 'y123@email.com', password: '123456789@2' } existingUser.id = 5 (dot notation) //

// 2-2 -> 지금 친 password 출력 // 지금 친 거는 request body에 들어있음
console.log(password); //console.log(req.body.password); -> const password = req.body.password 인데, const로 이미 passoword 안에 들어있으니까, password만 쳐도 됨/ 이제 찍자. 찍는 건 console.log로

//2-1 -> 위에서 select한 유저의 password 출력 (왜 select? 데이터베이스- mysql)
//위에서 select 유저의 이메일 가져오기
/*
const existingUser = await myDataSource.query(`
SELECT id, email FROM users WHERE email='${email}';
`) // password 기준으로 사람 찾아오면 안됨. email로 찾아야 함. // existingUSer 변수 중복으로 1번에 같이 넣어둠/ 근데 1번에서 이메일만 가져오는거니, 1번에서 패스워드, id도 가져오게 아예 코드 넣기
*/
// (sql문은 백엔드까지만 보내고, DB에는 안 보냄, 프>백>DB)\

// 2-2 -> 지금 친 패스워드와 데이터베이스에 있는 패스워드가 같은가
if (password !== existingUser[0].password) {
// if (req.body.password === userData.password) {
//지금 친 패스워드 = 변수 password --> 이거 맞는지 확인
const error = new Error("INVALID_PASSWORD");
error.statusCode = 400;
throw error;
}
// if 절을 'const inValidPassowrd = password !== existingUser[0].password; throwError(wrongPassword, 400, "AUTHENTICATION_FAILED");

//토큰 generate token / return 전에 token 만들기

// 1. use library allowing generating token
// 2. {"id": 10}
const token = jwt.sign({ id: existingUser[0].id }, "rekey"); /// mysql을 데이터베이스라고 부르고, 회원가입을 했으면, 데이터베이스에 회원정보가 잘 들어갔는지 mysql 가서 확인 (mysql을 데이터베이스로 부른다)

// 3. signature /// mysql 가서 접속, 데이터베이스 불러오기 (show databases;)/ 여기 안에 westagram 데이터베이스 사용할거야 use westagram; / westagram 안에 회원가입이니까 users 테이블을 다 보여줘 select * from users;/그러면 여기 아래에 추가된 사용자 이름, 비번, 아이디 뜨면 성공
return res.status(200).json({
message: "LOGIN_SUCCESS",
accessToken: token, //respond 보낼 때, 로그인 메세지와 함께 token 발행 (준다)
});
} catch (error) {
console.log(error);
}
}); //existingUser 는 객체로 key:value로 나오고, 그 안에 배열이 들어감, existingUser[0]={id: 5, email: 'y123@email.com', password: '123456789@2' } existingUser.id = 5 (dot notation) //

// 과제 3 DELETE
// 가장 마지막 user를 삭제하는 엔드포인트
app.delete("/users", async (req, res) => {
try {
//query문
} catch (err) {
console.log(err);
}
});

// 과제 4 UPDATE
// 1번 user의 이름을 'Code Kim'으로 바꾸어 보세요.

app.put("/users/1", async (req, res) => {
try {
const newName = req.body.data.name;
} catch (err) {
console.log(err);
}
});

// express app 으로 서버를 만듭니다.
const server = http.createServer(app);
// 서버를 시작하는 함수
const start = async () => {
try {
server.listen(8000, () => console.log(`Server is listening on 8000`));
} catch (err) {
console.error(err);
}
};

myDataSource.initialize().then(() => {
console.log("Data Source has been initialized!");
});

start();

혹시 코드를 잘못 쳤나 하고 보니,

로그인 과정에서 비밀번호 중복을 내가 위에서 이메일 중복확인한 소유자의 비밀번호가 아니라

아무나의 비밀번호와 중복되는지를 확인한 거였다. 

 

회원가입 시 비밀번호가 중복될 수 있지만,

로그인 시에는 비밀번호가 중복되면 안 되니까 (그 비밀번호를 가진 이메일 소유자가 많을 수 있으니, 로그인 시 기입한 이메일에 해당되는 비밀번호 인지 확인 해야 한다.) 


그러기 위해서는 

1. 원래 해야 하는 과정인, 회원가입 시 데이터베이스에 저장된 비밀번호와, 지금 유저가 작성한 비밀번호가 같은지 비교해보기

2. 그 비밀번호는 위에 이메일에 해당되는 소유자의 비밀번호여야 한다 

 

//2-1.아무나의 패스워드가 아니라, 위에 친 이메일 소유자에 해당되는 패스워드여야 함
//2-2.데이터베이스에 있는 패스워드가, 지금 친 패스워드랑 같은지 확인 / 그러려먼, 지금 친 패스워드와 이메일 출력
 

이걸 이제 컴퓨터 언어로 쪼개보면,

1) 지금 친 비밀번호를 가져와야 한다 (req.body에 지금 친 password 들어있음) 

2)위에 친 유저의 이메일 부터 가져오기 

3)그 이메일에 해당되는 비밀번호 가져온다 

 

 

 

2-1 -> 위에서 select한 유저의 password 출력 (왜 select? 데이터베이스- mysql)

 

위에서 select 유저의 이메일 가져오기 (mysql로)

 

const existingUser = await myDataSource.query(`
SELECT id, email FROM users WHERE email='${email}'; `) 

 

// password 기준으로 사람 찾아오면 안됨. email로 찾아야 함.
// 이미 위에 이메일에서 썼으니까, 여기서는 안 써도 됨. 대신 위에 이메일에서 ★패스워드를 위해 그거까지 고려해서 써줘야 함. 
// (sql문은 백엔드까지만 보내고, DB에는 안 보냄, 프>백>DB)

if ( existingUser[0]=0 ) {
const error = new Error("DUPLICATED_PASSWORD")
error.statusCode=400
throw error}

 

2-2 -> 지금 친 password 출력 // 지금 친 거는 request body에 들어있음

 

console.log(password) 

//const password = req.body.password 인데, const로 이미 passoword 안에 들어있으니까, password만 쳐도 됨/ 이제 찍자. 찍는 건 console.log로


일단 내가 해야할 것은

 

1. id:5 가 아닌, 다른 변수 써도 들어올 수 있게 해야 하고 

 

(id:___) 해놓으면 실행은 되는데, 에러가 나서 데이터베이스 상 테이블에 저장된 이메일 패스워드가 해당되는 

행의 id 값을 넣어두었다. 

 

2. 그리고 저기 비밀번호 중복 코드 더 하기