여유상점_09228 : 15) Double Form Submission, Passport.js Custom error handling , sending back message to client

오범준·2020년 9월 29일
0

http://www.passportjs.org/docs/authenticate/

Trial 1. Custom Callback Function

"router"

router.post('/login', function(req, res) {
passport.authenticate('local', function(err, user, info) {
console.log("let's see")
if (err) { return res.status(404).json({ message : 'failed'}) }
if (!user) {
// *** Display message without using flash option
// re-render the login form with a message
console.log("unauthorized !!!")
console.log("error message :", info.message)
return res.status(404).json({ message: info.message })
}
req.logIn(user, function(err) {
if (err) { return res.status(404).json({ message : 'failed'}) }
console.log("Authorization succeed")

    return res.status(200).json({message : info.message})
  });
})(req, res);

});

"Passport"

// LocalStrategy : for Client
passport.use('local', new LocalStrategy({
      usernameField: 'id',
      passwordField: 'password',
      // allow req variable in afterward callback function
      failWithError: true
  },
  // 사용자가 정보를 전달할 때마다 아래의 콜백함수가 실행된다
  async function(username, password, done,) {
      // 여기서 username은 사실상 우리가 입력하는 ID이다 
      console.log('LocalStrategy ', username, password)
      // 해당 id 의 user 가 존재하는지 확인한다 
      function FindUser(){
              return new Promise((resolve, reject) => {
              // write query
              const query = `SELECT * FROM member WHERE Id = '${username}'`;
              connection.db_rest.query(query, (err, results) => {
                  // err 발생시 아래의 코드를 통해 catch block이 error를 잡아낼 것이다 
                  if(err) {
                      console.log("User Finding Error")
                      reject(new Error(err.message)) 
                  }
                  // resolve는 최종 데이터를 전달한다 ( results를 response 에게...? )
                  resolve(results)
              })
          });
      } 

      FindUser()
      .then(result => {
          console.log(result)
          try {
              // 사용자가 존재하지 않는 다는 것
              if(response[0] == undefined){
                  console.log("no user matched")
              // 그렇지 않으면 login이 되지 않은 것이다
              // message : 'Incorrect password' 를 하게 되면
              // session-store 상에, 'flash' : { 'error' : ["Incorrect user"} 이라는 기록이 남는다 
              // done(null,false) : there is no error but there is no user either
                  return done(null, false, {message  :'Incorrect ID'})
              }else{
                  // 해당 사용자가 존재한다면 : ccmpare password
                  if( bcrypt.compare(password,response[0].Password )){
                      let authData = response[0]
                      // 참고: 2번째 인자로 false 가 아닌 값을 넣어준다 ( js 에서는 false 가 아닌 값을 true 로 친다 )
                      // authData 를 2번째 인자로 사용한다는 것은 : 로그인에 성공했으니, 성공한 사용자의 정보는 ~다 ! 라고 알려주는 것
                      // 그리고, 아래와 같이, done 함수의 2번째 인자로 false 가 아닌, 다른 값이 들어오면, passport.serialize 함수를 자동으로 호출한다
                      // 그런데 !!! 
                      // 아래 코드를 실행하려면 : passport.initialize() middleware를 사용해야 한다
                      // app.use(passport.initialize())를 사용해야 한다
                      return done(null, authData, { message :'success'})
                  }else{
                      return done(null, false, { message : 'Password is incorrect'})
                  }
              }
                 
          } catch (error) {
              console.log("error :", error)
              done(error, false,{ message : 'failed'} )
              return ;
          }
      })
      .catch(console.log)
  }
))

Problem

Problem here is that
passport.js local strategy is executed
after !!!

which means

as you can see in this console,

passport.js local strategy is executed after !!!

Problem of sending form twice

< front >

<form action="/auth/login" id = "loginForm" method="post" style="text-align:center">
      <legend><h2>일반회원 로그인</h2></legend>
      <hr />
      <input type="text" class="verify_id" name="id" id="myid" autofocus required placeholder="아이디" style="margin:10px auto; height:30px;font-size:16px;" ><br />
      <input type="password" class="verify_pw" name="password" required placeholder="비밀번호" style="margin:10px auto; height:30px;font-size:16px;" ><br />
      

      <div class="login-button" style=" width:200px; height:40px;font-size:16px;  ">
        <input id = "loginBtn" type="submit" value = "로그인" style = " letter-spacing: 1.2;font-weight: 600; margin-top: 1vh;width:100%; height: 100%;background-color:#19bf19;color:white;  border:none; border-radius:5px;" >
      </div>
      <a href="/google">
        <div style="box-shadow: 0px 5px 10px 0px rgba(0,0,0,.25);
        -o-box-shadow: 0px 5px 10px 0px rgba(0,0,0,.25);
        -ms-box-shadow: 0px 5px 10px 0px rgba(0,0,0,.25);
        -moz-box-shadow: 0px 5px 10px 0px rgba(0,0,0,.25); border-radius: 5px; width:200px; height:40px;font-size:16px;margin-top:1.5vh;background-color: lightskyblue; display: flex;align-items: center;justify-content: center;" >
          <i style = "color: white; margin-right:1vh;"class="fab fa-google-plus-g"></i><span style = "color: white; font-weight: 600;">Google Login</span>
        </div>
      </a>
      <h5><a href="/auth/register" class="login_text">회원가입 |</a>  <a href="/auth/findAccount" class="login_text" >아이디, 비밀번호 찾기</a><br /><br />
    </form>

As you see, in the "로그인" btn :
it is "button" type, not "submit" type

< Vanilla JS >

const loginForm = document.getElementById('loginForm')

loginBtn.addEventListener('submit', (event) => {
  const loginId = document.querySelector('#myid').value
  const loginPwd = document.querySelector('.verify_pw').value
  

So
1) With input type = "submit"
2) VS : FORM.addEventListenter ("submit")

it is sending twice

Solution

1) input type = "button"
2) VS

  • BUTTON.addEventListenter("click")
  • body : JSON.stringfy({
    username : ~
    password : ~
    })

3) Passport.js

        usernameField: 'username',
        passwordField: 'password',

4) match the name of the input

<input type="text" class="verify_id" name="id" id="myid" autofocus required placeholder="아이디" style="margin:10px auto; height:30px;font-size:16px;" ><br />
      <input type="password" class="verify_pw" name="password" required placeholder="비밀번호" style="margin:10px auto; height:30px;font-size:16px;" ><br />
profile
Dream of being "물빵개" ( Go abroad for Dance and Programming)

0개의 댓글