iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 9
0
Modern Web

30天Vue出Google SSO系列 第 18

Day 18. B2E-Token邏輯修改

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20200907/20118686ocj1UBqnpu.jpg

Token Bug 已經讓它飛很久了,是時候開殺了~


#Token邏輯修改

首先規劃要回到原本controller及module的初衷,controller負責中介,而資料處理留給module

#Step 1

開啟 /modules/user.module.js
新增 getSigninTokens,傳入值為 requestToken,把原來的code貼進來:

const getSigninTokens = (req, token) => {
    let signinTokens = [];
    signinTokens.push({ token: moduleResult.token, active: true });
    return signinTokens;
};

最下方記得匯出:

module.exports = {
    ...,
    getSigninTokens
};

/controllers/users.controller.js 改為呼叫module:

res.cookie('SigninTokens', userModule.getSigninTokens(req, moduleResult.token));

#Step 2

接著開始改寫邏輯!!
第一行判斷請求時帶入的token陣列,有就帶入,沒有就維持空陣列:

let signinTokens = req.cookies.SigninTokens ? req.cookies.SigninTokens : [];

#Step 3

將陣列中所有項目的啟用狀態都改為 false:

signinTokens.forEach(function (item) { item.active = false; });

#Step 4

從陣列中找到和登入帳號相同的項目:

let signinToken = signinTokens.find(function (item) {
    let accountId = jwt.verify(item.token, config.jwt.tokensecret, (error, decoded) => {
        return decoded.accountId;
    });
    return accountId === req.body.accountId;
});

這裡用到 JWT 的解密方法:

  • jwt.verify(要解密的Token, 密鑰, callback function)
  • decoded: 解密後的結果

#Step 5

陣列中有相同項目的話,代表有登入過,就直接更新Token和啟用狀態就好,沒有相同項目的話就push一筆新的上去:

if (signinToken) {
    signinToken.token = token;
    signinToken.active = true;
} else {
    signinTokens.push({ token, active: true });
}

#完整代碼

const getSigninTokens = (req, token) => {
    let signinTokens = req.cookies.SigninTokens ? req.cookies.SigninTokens : [];
    signinTokens.forEach(function (item) { item.active = false; });
    let signinToken = signinTokens.find(function (item) {
        let accountId = jwt.verify(item.token, config.jwt.tokensecret, (error, decoded) => {
            return decoded.accountId;
        });
        return accountId === req.body.accountId;
    });
    if (signinToken) {
        signinToken.token = token;
        signinToken.active = true;
    } else {
        signinTokens.push({ token, active: true });
    }
    return signinTokens;
};

改寫完就不會再有登入一次寫一次,登入一百次寫一百次的狀況囉!!


#Cookie簽章加密

cookie本身也能做簽章加密的動作
先說一下為什麼需要把cookie做簽章加密?
試想,既然我們都能在Chrome開發模式下看到它,想必竄改它的資料也不是什麼難事
而加上簽章加密後,對方無法知道密鑰,就算竄改了資料也能判斷出來,可有效做預防

#Step 1

開啟 app.js ,找到其中的 app.use(cookieParser()); 這段,將密鑰加進 cookieParser() 參數:

app.use(cookieParser('THISISMYCOOKIESECRET'));

密鑰可以寫進設定檔中引用

#Step 2

開啟 /controllers/users.controller.js
在存入 cookie 的程式碼後方加上 { signed: true } 參數設定,設定在寫入cookie時要做簽章加密的動作!!

res.cookie('SigninTokens', userModule.getSigninTokens(req, moduleResult.token), { signed: true });

#Step 3

開啟 /modules/user.module.js
原本取得 cookies 的部分都要改為抓已簽章的 signedCookies:

let signinTokens = req.signedCookies.SigninTokens ? req.signedCookies.SigninTokens : [];

三個地方改好就完成cookie簽章加密囉~
可以自己玩看看,到開發模式去竄改cookie值,會發現改了之後 req.signedCookies 這段就抓不到囉~


今日重點:

  • Token邏輯改為: 資料已存在就更新,不存在就新增
  • cookie簽章加密可預防資料被竄改

有需要改進或是任何意見建議歡迎下面留言~


上一篇
Day 17. B2E-加入Token
下一篇
Day 19. F2E&B2E-登入狀態驗證
系列文
30天Vue出Google SSO30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言