iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 16
1
Modern Web

Node JS-Back end見聞錄系列 第 16

Node.js-Backend見聞錄(15):實作-會員系統(四)-會員資料

Node.js-Backend見聞錄(15):實作-會員系統(四)-修改會員資料

前言

會員系統的部分,我們已經完成第二部分「會員登入」的功能了。接續往「修改會員資料」的功能出發。

修改會員資料需求

  • 提供一個可以讓會員修改資料的API。

資料結構

models資料夾新增個login_model.js的檔案。

.
├── app.js
├── bin
│   └── www
├── config
│   └── development_config.js
├── controllers
│   └── modify_controller.js
├── models
│   ├── connection_db.js
│   ├── encryption_model.js
│   ├── login_model.js
│   ├── register_model.js
│   ├── update_model.js
│   └── verification_model.js
├── package.json
├── public
│   ├── images
│   ├── javascripts
│   └── stylesheets
│       └── style.css
├── routes
│   ├── member.js
│   └── users.js
├── sevice
│   └── member_check.js
├── views
    ├── error.ejs
    └── index.ejs
├── .env
└── .gitignore

開始實作

從第一個需求推估若要達到這個功能,會員必須要先登入才能進行更換資料的動作。且在上篇文章中,已經實作出token功能。所以我們第一步要先做出能夠驗證會員的功能,也就是看針對token來做個驗證的動作。

驗證是否是會員

在上篇產生token的部分中,我們有故意將id也塞進去。藉由反推token的動作,可以從中取出id,等同於我們只要針對這個id的資料來進行更改動作即可。

首先,我們先寫一個驗證token及透過token來反推id的功能。在models資料夾的verification檔案中寫入:

const jwt = require('jsonwebtoken');
const config = require('../../config/development');

//進行token認證
module.exports = function verifyToken(token) {
    let tokenResult = "";
    const time = Math.floor(Date.now() / 1000);
    return new Promise((resolve, reject) => {
        //判斷token是否正確
        if (token) {
            jwt.verify(token, config.secret, function (err, decoded) {
                if (err) {
                    tokenResult = false;
                    resolve(tokenResult);
                    //token過期判斷
                } else if (decoded.exp <= time) {
                    tokenResult = false;
                    resolve(tokenResult);
                    //若正確
                } else {
                    tokenResult = decoded.data
                    resolve(tokenResult);
                }
            })
        }
    });
}

等同於要是今天token發生錯誤或過期就會回傳false。反之,則回傳反推過後的id值。接續來實作更改會員資料的資料庫功能。

再來接續到controllers資料中的modify_controller.js檔案來新增一個postUpdate的funciton:

postUpdate(req, res, next) {
    const token = req.headers['token'];
    //確定token是否有輸入
    if (check.checkNull(token) === true) {
        res.json({
            err: "請輸入token!"
        })
    } else if (check.checkNull(token) === false) {
        verify(token).then(tokenResult => {
            if (tokenResult === false ) {
                res.json({
                    result: {
                        status: "token錯誤。",
                        err: "請重新登入。"
                    }
                })
            } else {
                res.json({
                    test: "token正確"
                })
            }
        })
    }
}

給予API一個新的URL

給予這個API一個新的URL的端口,好讓我們能測試驗證token的部分是否能正常運作。在routes資料夾的member.js檔案中寫入:

var express = require('express');
var router = express.Router();

const MemberModifyMethod = require('../controllers/modify_controller');

memberModifyMethod = new MemberModifyMethod();

router.post('/register', memberModifyMethod.postRegister);

router.post('/login', memberModifyMethod.postLogin);

router.put('/update', memberModifyMethod.putUpdate);

module.exports = router;

測試

來測試看看token是否能正常進行判斷,這邊我們依舊使用Postman來運行。先透過呼叫/login的API來取得token。之後我們在使用token的值來做測試:

  • API URL: localhost:3000/update
  • HTTP method: PUT
  • headers
    • Content-Type: application/x-www-form-urlencoded
    • token: (由loginAPI取得的token值)

發現token偵測後是正確的,且id值也有成功被反推出來。

接續我們嘗試隨便更動token中其中的字母試試看會不會出錯:

其結果是符合我們預期的。

資料庫-會員資料更新

id部分已經在上個動作完成反推動作。接續就實作跟資料庫做聯動的部分:

models資料夾中新增一個update_model.js的檔案,並寫入:

const db = require('./connection_db');

module.exports = function customerEdit(id, memberUpdateData) {
    let result = {};
    return new Promise((resolve, reject) => {
        db.query('UPDATE member_info SET ? WHERE id = ?', [memberUpdateData, id], function (err, rows) {
            if (err) {
                console.log(err);
                result.status = "會員資料更新失敗。"
                result.err = "伺服器錯誤,請稍後在試!"
                reject(result);
                return;
            }
            result.status = "會員資料更新成功。"
            result.memberUpdateData = memberUpdateData
            resolve(result)
        })
    })
}

接著將controllers資料夾的modify_controller.js檔案中,其putUpdate function修改成:

putUpdate(req, res, next) {
    const token = req.headers['token'];
    //確定token是否有輸入
    if (check.checkNull(token) === true) {
        res.json({
            err: "請輸入token!"
        })
    } else if (check.checkNull(token) === false) {
        verify(token).then(tokenResult => {
            if (tokenResult === false) {
                res.json({
                    result: {
                        status: "token錯誤。",
                        err: "請重新登入。"
                    }
                })
            } else {
                const id = tokenResult;
                
                // 進行加密
                const password = encryption(req.body.password);

                const memberUpdateData = {
                    name: req.body.name,
                    password: password,
                    update_date: onTime()
                }
                updateAction(id, memberUpdateData).then(result => {
                    res.json({
                        result: result
                    })
                }, (err) => {
                    res.json({
                        result: err
                    })
                })
            }
        })
    }
}

測試

接續,我們使用之前第一個成功註冊的會員,其name為test,來進行測試:

  • 會員帳號:test@gmail.com
  • 會員密碼:1234

先進入/login API來取得token值。待取得後,將token值記錄下來並呼叫/update的API,這部分我們一樣藉由Postman來協助測試,並將其會員的name從test改為test1試試:

  • API URL: localhost:3000/update
  • HTTP method: PUT
  • headers
    • Content-Type: application/x-www-form-urlencoded
    • token: (由loginAPI取得的token值)
  • body
    • name: test1
    • password: 1234

修改完成後,我們再到terminal去進到MySQL那邊來輸入select * from member_info;指令,來觀察看看id為1的會員其name值有沒有變成test1。

其結果是有的,代表我們更改會員資料成功。

小結

這在我們已經完成了「修改會員資料」的功能了,接下來我們再來將「會員系統」這部分做個收尾,並添加些不一樣的功能。


上一篇
Node.js-Backend見聞錄(14):實作-會員系統(三)-會員登入
下一篇
Node.js-Backend見聞錄(16):實作-會員系統(五)-添加部分功能
系列文
Node JS-Back end見聞錄31

1 則留言

0
ip258852
iT邦新手 5 級 ‧ 2018-04-24 20:54:26

token判斷那邊都是resolve,
這樣會沒有rejection的狀態吧?

Hi, ip258852謝謝你的回覆。

是的,token判斷那部分只使用resolve來處理,反倒沒有使用reject

在「判斷token是否正確」這部分modelverification.js的處理方式為3種情況,分別是:

  1. token錯誤 -> 回傳false
  2. token過期 -> 回傳false
  3. token正確 -> 回傳夾雜在token裡面的訊息。

且都是用promise的resolve方式來進行回傳,並沒有再額外使用reject的方式來回傳錯誤的狀態。

等同於這部分的處理,在controllermodify_controller.js是直接沿用resolve的值來進行更進一步的判斷。

但若是要運用promise的reject的話,寫法就會變成:

const jwt = require('jsonwebtoken');
const config = require('../../config/development');

//進行token認證
module.exports = function verifyToken(token) {
    let tokenResult = '';
    const time = Math.floor(Date.now() / 1000);
    return new Promise((resolve, reject) => {
        //判斷token是否正確
        if (token) {
            jwt.verify(token, config.secret, function (err, decoded) {
                if (err) {
                    reject('token錯誤');
                    //token過期判斷
                } else if (decoded.exp <= time) {
                    reject('token已過期');
                    //若正確
                } else {
                    tokenResult = decoded.data
                    resolve(tokenResult);
                }
            })
        }
    });
}
postUpdate(req, res, next) {
  const token = req.headers['token'];
  //確定token是否有輸入
  if (check.checkNull(token) === true) {
      res.json({
          err: "請輸入token!"
      })
  } else if (check.checkNull(token) === false) {
      verify(token).then(tokenResult => {
        res.json({
          result: {
            status: 'token正確',
          }
        })
      }, (err) => {
        res.json({
          err
        })
      })
  }
}

這樣的寫法也能達到在文章中所提到的效果。

OK 懂了
3Q

我要留言

立即登入留言